home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 19 / Amiga Plus Leser CD 19.iso / Tools / Development / qstat25b / qstat.c < prev    next >
C/C++ Source or Header  |  2002-11-18  |  169KB  |  6,722 lines

  1. /*
  2.  * qstat 2.5b
  3.  * by Steve Jankowski
  4.  * steve@qstat.org
  5.  * http://www.qstat.org
  6.  *
  7.  * Thanks to Per Hammer for the OS/2 patches (per@mindbend.demon.co.uk)
  8.  * Thanks to John Ross Hunt for the OpenVMS Alpha patches (bigboote@ais.net)
  9.  * Thanks to Scott MacFiggen for the quicksort code (smf@webmethods.com)
  10.  * Thanks to Simon Garner for the XML patch (sgarner@gameplanet.co.nz)
  11.  *
  12.  * Inspired by QuakePing by Len Norton
  13.  *
  14.  * Copyright 1996,1997,1998,1999 by Steve Jankowski
  15.  *
  16.  * Licensed under the Artistic License, see LICENSE.txt for license terms
  17.  */
  18.  
  19. #define VERSION "2.5b"
  20. char *qstat_version= VERSION;
  21.  
  22. /* OS/2 defines */
  23. #ifdef __OS2__
  24. #define BSD_SELECT
  25. #endif
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <errno.h>
  30. #include <sys/types.h>
  31. #include <string.h>
  32. #include <ctype.h>
  33.  
  34. #define QUERY_PACKETS
  35. #include "qstat.h"
  36. #include "config.h"
  37.  
  38.  
  39. #ifdef _ISUNIX
  40. #include <unistd.h>
  41. #include <sys/socket.h>
  42. #ifndef VMS
  43. #include <sys/param.h>
  44. #endif
  45. #include <sys/time.h>
  46. #include <netinet/in.h>
  47. #include <netinet/tcp.h>
  48. #include <netdb.h>
  49. #include <arpa/inet.h>
  50.  
  51. #ifndef F_SETFL
  52. #include <fcntl.h>
  53. #endif
  54.  
  55. #ifdef __hpux
  56. extern int h_errno;
  57. #define STATIC static
  58. #else
  59. #define STATIC
  60. #endif
  61.  
  62. #define INVALID_SOCKET -1
  63. #define SOCKET_ERROR -1
  64. #ifndef INADDR_NONE
  65. #define INADDR_NONE ~0
  66. #endif
  67. #define sockerr()    errno
  68. #endif /* _ISUNIX */
  69.  
  70. #ifdef _WIN32
  71. #ifndef FD_SETSIZE
  72. #define FD_SETSIZE 256
  73. #endif
  74. #include <winsock.h>
  75. #include <sys/timeb.h>
  76. #define close(a) closesocket(a)
  77. int gettimeofday(struct timeval *now, void *blah)
  78. {
  79.     struct timeb timeb;
  80.     ftime( &timeb);
  81.     now->tv_sec= timeb.time;
  82.     now->tv_usec= (unsigned int)timeb.millitm * 1000;
  83.     return 0;
  84. }
  85. #define sockerr()    WSAGetLastError()
  86. #define strcasecmp      stricmp
  87. #define strncasecmp     strnicmp
  88. #define STATIC
  89. #ifndef EADDRINUSE
  90. #define EADDRINUSE    WSAEADDRINUSE
  91. #endif
  92. #endif /* _WIN32 */
  93.  
  94. #ifdef __OS2__
  95. #include <sys/socket.h>
  96. #include <sys/select.h>
  97. #include <sys/time.h>
  98. #include <netinet/in.h>
  99. #include <netdb.h>
  100. #include <utils.h>
  101.  
  102. #define INVALID_SOCKET -1
  103. #define SOCKET_ERROR -1
  104. #define close(a)        soclose(a)
  105. #endif /* __OS2__ */
  106.  
  107.  
  108. #ifndef FD_SETSIZE
  109. #define FD_SETSIZE 64
  110. #endif
  111.  
  112. /* Figure out whether to use poll() or select()
  113. */
  114. #ifndef USE_POLL
  115. #ifndef USE_SELECT
  116.  
  117. #ifdef sun
  118. #define USE_POLL
  119. #endif
  120. #ifdef linux
  121. #define USE_POLL
  122. #include <poll.h>
  123. #endif
  124. #ifdef __linux__
  125. #define USE_POLL
  126. #include <poll.h>
  127. #endif
  128. #ifdef __linux
  129. #define USE_POLL
  130. #include <poll.h>
  131. #endif
  132. #ifdef __hpux
  133. #define USE_POLL
  134. #include <sys/poll.h>
  135. #endif
  136. #ifdef __OpenBSD__
  137. #define USE_POLL
  138. #include <sys/poll.h>
  139. #endif
  140. #ifdef _AIX
  141. #define USE_POLL
  142. #include <poll.h>
  143. #endif
  144. #ifdef _WIN32
  145. #define USE_SELECT
  146. #endif
  147. #ifdef __EMX__
  148. #define USE_SELECT
  149. #endif
  150.  
  151. #endif
  152. #endif
  153.  
  154. /* If did not chose, then use select()
  155. */
  156. #ifndef USE_POLL
  157. #ifndef USE_SELECT
  158. #define USE_SELECT
  159. #endif
  160. #endif
  161.  
  162. server_type *types;
  163. int n_server_types;
  164.  
  165. /* Values set by command-line arguments
  166.  */
  167.  
  168.  
  169. int hostname_lookup= 0;        /* set if -H was specified */
  170. int new_style= 1;        /* unset if -old was specified */
  171. int n_retries= DEFAULT_RETRIES;
  172. int retry_interval= DEFAULT_RETRY_INTERVAL;
  173. int master_retry_interval= DEFAULT_RETRY_INTERVAL*4;
  174. int get_player_info= 0;
  175. int get_server_rules= 0;
  176. int up_servers_only= 0;
  177. int no_full_servers= 0;
  178. int no_empty_servers= 0;
  179. int no_header_display= 0;
  180. int raw_display= 0;
  181. char *raw_delimiter= "\t";
  182. int player_address= 0;
  183. int hex_player_names= 0;
  184. int strip_carets= 1;
  185. int max_simultaneous= MAXFD_DEFAULT;
  186. int html_names= -1;
  187. extern int html_mode;
  188. int raw_arg= 0;
  189. int show_game_in_raw= 0;
  190. int progress= 0;
  191. int num_servers_total= 0;
  192. int num_players_total= 0;
  193. int num_servers_returned= 0;
  194. int num_servers_timed_out= 0;
  195. int num_servers_down= 0;
  196. server_type* default_server_type= NULL;
  197. FILE *OF;        /* output file */
  198. unsigned int source_ip= INADDR_ANY;
  199. unsigned short source_port_low= 0;
  200. unsigned short source_port_high= 0;
  201. unsigned short source_port= 0;
  202.  
  203. #define ENCODING_LATIN_1  1
  204. #define ENCODING_UTF_8    8
  205. int xml_display= 0;
  206. int xml_encoding= ENCODING_LATIN_1;
  207.  
  208. #define SUPPORTED_SERVER_SORT    "pgihn"
  209. #define SUPPORTED_PLAYER_SORT    "PFT"
  210. #define SUPPORTED_SORT_KEYS    "l" SUPPORTED_SERVER_SORT SUPPORTED_PLAYER_SORT
  211. char sort_keys[32];
  212. int player_sort= 0;
  213. int server_sort= 0;
  214.  
  215. void sort_servers( struct qserver **array, int size);
  216. void sort_players( struct qserver *server);
  217. int server_compare( struct qserver *one, struct qserver *two);
  218. int player_compare( struct player *one, struct player *two);
  219.  
  220. int show_errors= 0;
  221.  
  222. #define DEFAULT_COLOR_NAMES_RAW        0
  223. #define DEFAULT_COLOR_NAMES_DISPLAY    1
  224. int color_names= -1;
  225.  
  226. #define SECONDS 0
  227. #define CLOCK_TIME 1
  228. #define STOPWATCH_TIME 2
  229. #define DEFAULT_TIME_FMT_RAW        SECONDS
  230. #define DEFAULT_TIME_FMT_DISPLAY    CLOCK_TIME
  231. int time_format= -1;
  232.  
  233. struct qserver *servers= NULL;
  234. struct qserver **last_server= &servers;
  235. struct qserver **connmap= NULL;
  236. int max_connmap;
  237. struct qserver *last_server_bind= NULL;
  238. int connected= 0;
  239. time_t run_timeout= 0;
  240. time_t start_time;
  241. int waiting_for_masters;
  242.  
  243. #define ADDRESS_HASH_LENGTH    503
  244. static struct qserver **server_hash[ADDRESS_HASH_LENGTH];
  245. static unsigned int server_hash_len[ADDRESS_HASH_LENGTH];
  246.  
  247. char *DOWN= "DOWN";
  248. char *SYSERROR= "SYSERROR";
  249. char *TIMEOUT= "TIMEOUT";
  250. char *MASTER= "MASTER";
  251. char *SERVERERROR= "ERROR";
  252. char *HOSTNOTFOUND= "HOSTNOTFOUND";
  253.  
  254. int display_prefix= 0;
  255. char *current_filename;
  256. int current_fileline;
  257.  
  258. int count_bits( int n);
  259.  
  260. static int wait_for_timeout( unsigned int ms);
  261. static void finish_output();
  262. static void decode_stefmaster_packet( struct qserver *server, char *pkt, int pktlen);
  263. static void decode_q3master_packet( struct qserver *server, char *pkt, int pktlen);
  264. static int combine_packets( struct qserver *server);
  265. static int unreal_player_info_key( char *s, char *end);
  266.  
  267.  
  268.  
  269. struct rule * add_rule( struct qserver *server, char *key, char *value,
  270.     int flags);
  271. #define NO_FLAGS 0
  272. #define NO_VALUE_COPY 1
  273. #define CHECK_DUPLICATE_RULES 2
  274.  
  275. /* MODIFY HERE
  276.  * Change these functions to display however you want
  277.  */
  278. void
  279. display_server(
  280.     struct qserver *server
  281. )
  282. {
  283.     char name[100], prefix[64];
  284.  
  285.     if ( player_sort)
  286.     sort_players( server);
  287.  
  288.     if ( raw_display)  {
  289.     raw_display_server( server);
  290.     return;
  291.     }
  292.     else if ( xml_display) {
  293.     xml_display_server( server);
  294.     return;
  295.     }
  296.     if ( have_server_template())  {
  297.     template_display_server( server);
  298.     return;
  299.     }
  300.  
  301.     if ( display_prefix)
  302.     sprintf( prefix, "%-4s ", server->type->type_prefix);
  303.     else
  304.     prefix[0]='\0';
  305.  
  306.     if ( server->server_name == DOWN)  {
  307.     if ( ! up_servers_only)
  308.         fprintf( OF, "%s%-16s %10s\n", prefix,
  309.         (hostname_lookup) ? server->host_name : server->arg, DOWN);
  310.     return;
  311.     }
  312.     if ( server->server_name == TIMEOUT)  {
  313.     if ( server->flags & FLAG_BROADCAST && server->n_servers)
  314.         fprintf( OF, "%s%-16s %d servers\n", prefix,
  315.         server->arg, server->n_servers);
  316.     else if ( ! up_servers_only)
  317.         fprintf( OF, "%s%-16s no response\n", prefix,
  318.         (hostname_lookup) ? server->host_name : server->arg);
  319.     return;
  320.     }
  321.  
  322.     if ( server->type->master)  {
  323.     display_qwmaster(server);
  324.     return;
  325.     }
  326.  
  327.     if ( no_full_servers && server->num_players >= server->max_players)
  328.     return;
  329.  
  330.     if ( no_empty_servers && server->num_players == 0)
  331.     return;
  332.  
  333.     if ( server->error != NULL)  {
  334.     fprintf( OF, "%s%-21s ERROR <%s>\n",
  335.         prefix,
  336.         (hostname_lookup) ? server->host_name : server->arg,
  337.         server->error);
  338.     return;
  339.     }
  340.  
  341.     if ( new_style)  {
  342.     char *game= get_qw_game( server);
  343.     int map_name_width= 8, game_width=0;
  344.     switch( server->type->id)  {
  345.     case QW_SERVER: case Q2_SERVER: case Q3_SERVER:
  346.         game_width= 9; break;
  347.     case TRIBES2_SERVER:
  348.         map_name_width= 14; game_width= 8; break;
  349.     case HL_SERVER:
  350.         map_name_width= 12; break;
  351.     default:
  352.         break;
  353.     }
  354.     fprintf( OF, "%s%-21s %2d/%2d %*s %6d / %1d  %*s %s\n",
  355.         prefix,
  356.         (hostname_lookup) ? server->host_name : server->arg,
  357.         server->num_players, server->max_players,
  358.         map_name_width, (server->map_name) ? server->map_name : "?",
  359.         server->ping_total/server->n_requests,
  360.         server->n_retries,
  361.         game_width, game,
  362.         xform_name(server->server_name, server));
  363.     if ( get_server_rules)
  364.         server->type->display_rule_func( server);
  365.     if ( get_player_info)
  366.         server->type->display_player_func( server);
  367.     }
  368.     else  {
  369.     sprintf( name, "\"%s\"", server->server_name);
  370.     fprintf( OF, "%-16s %10s map %s at %22s %d/%d players %d ms\n", 
  371.         (hostname_lookup) ? server->host_name : server->arg,
  372.         name, server->map_name,
  373.         server->address, server->num_players, server->max_players,
  374.         server->ping_total/server->n_requests);
  375.     }
  376. }
  377.  
  378. void
  379. display_qwmaster( struct qserver *server)
  380. {
  381.     char *prefix;
  382.     prefix= server->type->type_prefix;
  383.  
  384.     if ( server->error != NULL)
  385.     fprintf( OF, "%s %-17s ERROR <%s>\n", prefix,
  386.         (hostname_lookup) ? server->host_name : server->arg,
  387.         server->error);
  388.     else
  389.     fprintf( OF, "%s %-17s %d servers %6d / %1d\n", prefix,
  390.         (hostname_lookup) ? server->host_name : server->arg,
  391.         server->n_servers,
  392.         server->ping_total/server->n_requests,
  393.         server->n_retries);
  394. }
  395.  
  396. void
  397. display_header()
  398. {
  399.     if ( ! no_header_display)
  400.     fprintf( OF, "%-16s %8s %8s %15s    %s\n", "ADDRESS", "PLAYERS", "MAP",
  401.         "RESPONSE TIME", "NAME");
  402. }
  403.  
  404. void
  405. display_server_rules( struct qserver *server)
  406. {
  407.     struct rule *rule;
  408.     int printed= 0;
  409.     rule= server->rules;
  410.     for ( ; rule != NULL; rule= rule->next)  {
  411.     if ( (server->type->id != Q_SERVER &&
  412.         server->type->id != H2_SERVER) || ! is_default_rule( rule)) {
  413.         fprintf( OF, "%c%s=%s", (printed)?',':'\t', rule->name, rule->value);
  414.         printed++;
  415.     }
  416.     }
  417.     if ( printed)
  418.     fputs( "\n", OF);
  419. }
  420.  
  421. void
  422. display_q_player_info( struct qserver *server)
  423. {
  424.     char fmt[128];
  425.     struct player *player;
  426.  
  427.     strcpy( fmt, "\t#%-2d %3d frags %9s ");
  428.  
  429.     if ( color_names)
  430.     strcat( fmt, "%9s:%-9s ");
  431.     else
  432.     strcat( fmt, "%2d:%-2d ");
  433.     if ( player_address)
  434.     strcat( fmt, "%22s ");
  435.     else
  436.     strcat( fmt, "%s");
  437.     strcat( fmt, "%s\n");
  438.  
  439.     player= server->players;
  440.     for ( ; player != NULL; player= player->next)  {
  441.     fprintf( OF, fmt,
  442.         player->number,
  443.         player->frags,
  444.         play_time(player->connect_time,1),
  445.         quake_color(player->shirt_color),
  446.         quake_color(player->pants_color),
  447.         (player_address)?player->address:"",
  448.         xform_name( player->name, server));
  449.     }
  450. }
  451.  
  452. void
  453. display_qw_player_info( struct qserver *server)
  454. {
  455.     char fmt[128];
  456.     struct player *player;
  457.  
  458.     strcpy( fmt, "\t#%-6d %3d frags %6s@%-5s %8s");
  459.  
  460.     if ( color_names)
  461.     strcat( fmt, "%9s:%-9s ");
  462.     else
  463.     strcat( fmt, "%2d:%-2d ");
  464.     strcat( fmt, "%s\n");
  465.  
  466.     player= server->players;
  467.     for ( ; player != NULL; player= player->next)  {
  468.     fprintf( OF, fmt,
  469.         player->number,
  470.         player->frags,
  471.         play_time(player->connect_time,0),
  472.         ping_time(player->ping),
  473.         player->skin ? player->skin : "",
  474.         quake_color(player->shirt_color),
  475.         quake_color(player->pants_color),
  476.         xform_name( player->name, server));
  477.     }
  478. }
  479.  
  480. void
  481. display_q2_player_info( struct qserver *server)
  482. {
  483.     struct player *player;
  484.  
  485.     player= server->players;
  486.     for ( ; player != NULL; player= player->next)  {
  487.     if ( server->flags & FLAG_PLAYER_TEAMS)
  488.         fprintf( OF, "\t%3d frags team#%d %8s  %s\n", 
  489.         player->frags,
  490.         player->team,
  491.         ping_time(player->ping),
  492.         xform_name( player->name, server));
  493.     else
  494.         fprintf( OF, "\t%3d frags %8s  %s\n", 
  495.         player->frags,
  496.         ping_time(player->ping),
  497.         xform_name( player->name, server));
  498.     }
  499. }
  500.  
  501. void
  502. display_unreal_player_info( struct qserver *server)
  503. {
  504.     struct player *player;
  505.  
  506.     player= server->players;
  507.     for ( ; player != NULL; player= player->next)  {
  508.     fprintf( OF, "\t%3d frags team#%-3d %7s %s\n", 
  509.         player->frags,
  510.         player->team,
  511.         ping_time(player->ping),
  512.         xform_name( player->name, server));
  513.     }
  514. }
  515.  
  516. void
  517. display_shogo_player_info( struct qserver *server)
  518. {
  519.     struct player *player;
  520.  
  521.     player= server->players;
  522.     for ( ; player != NULL; player= player->next)  {
  523.     fprintf( OF, "\t%3d frags %8s %s\n", 
  524.         player->frags,
  525.         ping_time(player->ping),
  526.         xform_name( player->name, server));
  527.     }
  528. }
  529.  
  530. void
  531. display_halflife_player_info( struct qserver *server)
  532. {
  533.     struct player *player;
  534.  
  535.     player= server->players;
  536.     for ( ; player != NULL; player= player->next)  {
  537.     fprintf( OF, "\t%3d frags %8s %s\n", 
  538.         player->frags,
  539.         play_time( player->connect_time,1),
  540.         xform_name( player->name, server));
  541.     }
  542. }
  543.  
  544. void
  545. display_tribes_player_info( struct qserver *server)
  546. {
  547.     struct player *player;
  548.  
  549.     player= server->players;
  550.     for ( ; player != NULL; player= player->next)  {
  551.     fprintf( OF, "\t%4d score team#%d %8s %s\n", 
  552.         player->frags,
  553.         player->team,
  554.         ping_time( player->ping),
  555.         xform_name( player->name, server));
  556.     }
  557. }
  558.  
  559. void
  560. display_tribes2_player_info( struct qserver *server)
  561. {
  562.     struct player *player;
  563.  
  564.     player= server->players;
  565.     for ( ; player != NULL; player= player->next)  {
  566.     fprintf( OF, "\tscore %4d %14s %s\n", 
  567.         player->frags,
  568.         player->team_name ? player->team_name : (player->number == TRIBES_TEAM ? "TEAM" : "?"),
  569.         xform_name( player->name, server));
  570.     }
  571. }
  572.  
  573. void
  574. display_bfris_player_info( struct qserver *server)
  575. {
  576.     struct player *player;
  577.  
  578.     player= server->players;
  579.     for ( ; player != NULL; player= player->next)  {
  580.       fprintf( OF, "\ttid: %d, ship: %d, team: %s, ping: %d, score: %d, kills: %d, name: %s\n",
  581.          player->number,
  582.          player->ship,
  583.          player->team_name,
  584.          player->ping,
  585.          player->score,
  586.          player->frags,
  587.          xform_name( player->name, server));
  588.     }
  589. }
  590.  
  591. void
  592. display_descent3_player_info( struct qserver *server)
  593. {
  594.     struct player *player;
  595.  
  596.     player= server->players;
  597.     for ( ; player != NULL; player= player->next)  {
  598.     fprintf( OF, "\t%3d frags %3d deaths team#%-3d %7s %s\n", 
  599.         player->frags,
  600.         player->deaths,
  601.         player->team,
  602.         ping_time(player->ping),
  603.         xform_name( player->name, server));
  604.     }
  605. }
  606.  
  607. char *
  608. get_qw_game( struct qserver *server)
  609. {
  610.     struct rule *rule;
  611.     if ( server->type->game_rule == NULL || *server->type->game_rule == '\0')
  612.     return "";
  613.     rule= server->rules;
  614.     for ( ; rule != NULL; rule= rule->next)
  615.     if ( strcmp( rule->name, server->type->game_rule) == 0)  {
  616.         if ( server->type->id == Q3_SERVER &&
  617.             strcmp( rule->value, "baseq3") == 0)
  618.         return "";
  619.         return rule->value;
  620.     }
  621.     rule= server->rules;
  622.     for ( ; rule != NULL; rule= rule->next)
  623.     if ( strcmp( rule->name, "game") == 0)
  624.         return rule->value;
  625.     return "";
  626. }
  627.  
  628. /* Raw output for web master types
  629.  */
  630.  
  631. #define RD raw_delimiter
  632.  
  633. void
  634. raw_display_server( struct qserver *server)
  635. {
  636.     char *prefix;
  637.     int ping_time;
  638.     prefix= server->type->type_prefix;
  639.  
  640.     if ( server->n_requests)
  641.     ping_time= server->ping_total/server->n_requests;
  642.     else
  643.     ping_time= 0;
  644.  
  645.     if ( server->server_name == DOWN)  {
  646.     if ( ! up_servers_only)
  647.         fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%s\n\n",
  648.         prefix,
  649.         raw_arg, RD, raw_arg, server->arg,
  650.         RD, (hostname_lookup)?server->host_name:server->arg,
  651.         RD, DOWN);
  652.     return;
  653.     }
  654.     if ( server->server_name == TIMEOUT)  {
  655.     if ( server->flags & FLAG_BROADCAST && server->n_servers)
  656.         fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%d\n", prefix,
  657.         raw_arg, RD, raw_arg, server->arg,
  658.         RD, server->arg,
  659.         RD, server->n_servers);
  660.     else if ( ! up_servers_only)
  661.         fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%s\n\n",
  662.         prefix,
  663.         raw_arg, RD, raw_arg, server->arg,
  664.         RD, (hostname_lookup)?server->host_name:server->arg,
  665.         RD, TIMEOUT);
  666.     return;
  667.     }
  668.  
  669.     if ( server->error != NULL)  {
  670.         fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s",
  671.         prefix,
  672.         raw_arg, RD, raw_arg, server->arg,
  673.         RD, (hostname_lookup) ? server->host_name : server->arg,
  674.         RD, "ERROR",
  675.         RD, server->error);
  676.     }
  677.     else if ( server->type->flags & TF_RAW_STYLE_QUAKE)  {
  678.         fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s" "%s%d" "%s%s" "%s%d" "%s%d" "%s%d" "%s%d" "%s%s",
  679.         prefix,
  680.         raw_arg, RD, raw_arg, server->arg,
  681.         RD, (hostname_lookup) ? server->host_name : server->arg,
  682.         RD, xform_name( server->server_name, server),
  683.         RD, server->address,
  684.         RD, server->protocol_version,
  685.         RD, server->map_name,
  686.         RD, server->max_players,
  687.         RD, server->num_players,
  688.         RD, ping_time,
  689.         RD, server->n_retries,
  690.         show_game_in_raw ? RD : "", show_game_in_raw ? get_qw_game(server) : ""
  691.         );
  692.     }
  693.     else if ( server->type->flags & TF_RAW_STYLE_TRIBES)  {
  694.     fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s" "%s%d" "%s%d",
  695.         prefix,
  696.         raw_arg, RD, raw_arg, server->arg,
  697.         RD, (hostname_lookup) ? server->host_name : server->arg,
  698.         RD, xform_name( server->server_name, server),
  699.         RD, (server->map_name) ? server->map_name : "?",
  700.         RD, server->num_players,
  701.         RD, server->max_players
  702.     );
  703.     }
  704.     else if ( server->type->master)  {
  705.         fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%d",
  706.         prefix,
  707.         raw_arg, RD, raw_arg, server->arg,
  708.         RD, (hostname_lookup) ? server->host_name : server->arg,
  709.         RD, server->n_servers
  710.     );
  711.     }
  712.     else  {
  713.         fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s" "%s%d" "%s%d" "%s%d" "%s%d" "%s%s",
  714.         prefix,
  715.         raw_arg, RD, raw_arg, server->arg,
  716.         RD, (hostname_lookup) ? server->host_name : server->arg,
  717.         RD, xform_name( server->server_name, server),
  718.         RD, (server->map_name) ? server->map_name : "?",
  719.         RD, server->max_players,
  720.         RD, server->num_players,
  721.         RD, ping_time,
  722.         RD, server->n_retries,
  723.         show_game_in_raw ? RD : "", show_game_in_raw ? get_qw_game(server) : ""
  724.         );
  725.     }
  726.     fputs( "\n", OF);
  727.  
  728.     if ( server->type->master || server->error != NULL)  {
  729.     fputs( "\n", OF);
  730.     return;
  731.     }
  732.  
  733.     if ( get_server_rules)
  734.     server->type->display_raw_rule_func( server);
  735.     if ( get_player_info)
  736.     server->type->display_raw_player_func( server);
  737.     fputs( "\n", OF);
  738. }
  739.  
  740. void
  741. raw_display_server_rules( struct qserver *server)
  742. {
  743.     struct rule *rule;
  744.     int printed= 0;
  745.     rule= server->rules;
  746.     for ( ; rule != NULL; rule= rule->next)  {
  747.     if ( server->type->id == TRIBES2_SERVER)  {
  748.         char *v;
  749.         for ( v= rule->value; *v; v++)
  750.         if ( *v == '\n') *v= ' ';
  751.     }
  752.     fprintf( OF, "%s%s=%s", (printed)?RD:"", rule->name, rule->value);
  753.     printed++;
  754.     }
  755.     if ( server->missing_rules)
  756.     fprintf( OF, "%s?", (printed)?RD:"");
  757.     fputs( "\n", OF);
  758. }
  759.  
  760. void
  761. raw_display_q_player_info( struct qserver *server)
  762. {
  763.     char fmt[128];
  764.     struct player *player;
  765.  
  766.     strcpy( fmt, "%d" "%s%s" "%s%s" "%s%d" "%s%s");
  767.     if ( color_names)
  768.     strcat( fmt, "%s%s" "%s%s");
  769.     else
  770.     strcat( fmt, "%s%d" "%s%d");
  771.  
  772.     player= server->players;
  773.     for ( ; player != NULL; player= player->next)  {
  774.     fprintf( OF, fmt,
  775.         player->number,
  776.         RD, xform_name( player->name, server),
  777.         RD, player->address,
  778.         RD, player->frags,
  779.         RD, play_time(player->connect_time,1),
  780.         RD, quake_color(player->shirt_color),
  781.         RD, quake_color(player->pants_color)
  782.     );
  783.     fputs( "\n", OF);
  784.     }
  785. }
  786.  
  787. void
  788. raw_display_qw_player_info( struct qserver *server)
  789. {
  790.     char fmt[128];
  791.     struct player *player;
  792.  
  793.     strcpy( fmt, "%d" "%s%s" "%s%d" "%s%s");
  794.     if ( color_names)
  795.     strcat( fmt, "%s%s" "%s%s");
  796.     else
  797.     strcat( fmt, "%s%d" "%s%d");
  798.     strcat( fmt, "%s%d" "%s%s");
  799.  
  800.     player= server->players;
  801.     for ( ; player != NULL; player= player->next)  {
  802.     fprintf( OF, fmt,
  803.         player->number,
  804.         RD, xform_name( player->name, server),
  805.         RD, player->frags,
  806.         RD, play_time(player->connect_time,1),
  807.         RD, quake_color(player->shirt_color),
  808.         RD, quake_color(player->pants_color),
  809.         RD, player->ping,
  810.         RD, player->skin ? player->skin : ""
  811.     );
  812.     fputs( "\n", OF);
  813.     }
  814. }
  815.  
  816. void
  817. raw_display_q2_player_info( struct qserver *server)
  818. {
  819.     static char fmt[24] = "%s" "%s%d" "%s%d";
  820.     static char fmt_team[24] = "%s" "%s%d" "%s%d" "%s%d";
  821.     struct player *player;
  822.  
  823.     player= server->players;
  824.     for ( ; player != NULL; player= player->next)  {
  825.     if ( server->flags & FLAG_PLAYER_TEAMS)
  826.         fprintf( OF, fmt_team,
  827.         xform_name( player->name, server),
  828.         RD, player->frags,
  829.         RD, player->ping,
  830.         RD, player->team
  831.         );
  832.     else
  833.         fprintf( OF, fmt,
  834.         xform_name( player->name, server),
  835.         RD, player->frags,
  836.         RD, player->ping
  837.         );
  838.     fputs( "\n", OF);
  839.     }
  840. }
  841.  
  842. void
  843. raw_display_unreal_player_info( struct qserver *server)
  844. {
  845.     static char fmt[28]= "%s" "%s%d" "%s%d" "%s%d" "%s%s" "%s%s" "%s%s";
  846.     struct player *player;
  847.  
  848.     player= server->players;
  849.     for ( ; player != NULL; player= player->next)  {
  850.     fprintf( OF, fmt,
  851.         xform_name( player->name, server),
  852.         RD, player->frags,
  853.         RD, player->ping,
  854.         RD, player->team,
  855.         RD, player->skin ? player->skin : "",
  856.         RD, player->mesh ? player->mesh : "",
  857.         RD, player->face ? player->face : ""
  858.     );
  859.     fputs( "\n", OF);
  860.     }
  861. }
  862.  
  863. void
  864. raw_display_halflife_player_info( struct qserver *server)
  865. {
  866.     static char fmt[24]= "%s" "%s%d" "%s%s";
  867.     struct player *player;
  868.  
  869.     player= server->players;
  870.     for ( ; player != NULL; player= player->next)  {
  871.     fprintf( OF, fmt,
  872.         xform_name( player->name, server),
  873.         RD, player->frags,
  874.         RD, play_time( player->connect_time,1)
  875.     );
  876.     fputs( "\n", OF);
  877.     }
  878. }
  879.  
  880. void
  881. raw_display_tribes_player_info( struct qserver *server)
  882. {
  883.     static char fmt[24]= "%s" "%s%d" "%s%d" "%s%d" "%s%d";
  884.     struct player *player;
  885.  
  886.     player= server->players;
  887.     for ( ; player != NULL; player= player->next)  {
  888.     fprintf( OF, fmt,
  889.         xform_name( player->name, server),
  890.         RD, player->frags,
  891.         RD, player->ping,
  892.         RD, player->team,
  893.         RD, player->packet_loss
  894.     );
  895.     fputs( "\n", OF);
  896.     }
  897. }
  898.  
  899. void
  900. raw_display_tribes2_player_info( struct qserver *server)
  901. {
  902.     static char fmt[]= "%s" "%s%d" "%s%d" "%s%s" "%s%s" "%s%s";
  903.     struct player *player;
  904.     char *type;
  905.  
  906.     player= server->players;
  907.     for ( ; player != NULL; player= player->next)  {
  908.     switch( player->type_flag)  {
  909.     case PLAYER_TYPE_BOT: type= "Bot"; break;
  910.     case PLAYER_TYPE_ALIAS: type= "Alias"; break;
  911.     default: type= ""; break;
  912.     }
  913.     fprintf( OF, fmt,
  914.         xform_name( player->name, server),
  915.         RD, player->frags,
  916.         RD, player->team,
  917.         RD, player->team_name ? player->team_name : "TEAM",
  918.         RD, type,
  919.         RD, player->tribe_tag ? xform_name(player->tribe_tag,server) : ""
  920.     );
  921.     fputs( "\n", OF);
  922.     }
  923. }
  924.  
  925. void
  926. raw_display_bfris_player_info( struct qserver *server)
  927. {
  928.   static char fmt[] = "%d" "%s%d" "%s%s" "%s%d" "%s%d" "%s%d" "%s%s";
  929.   struct player *player;
  930.  
  931.   player= server->players;
  932.   for ( ; player != NULL; player= player->next)  {
  933.     fprintf( OF, fmt,
  934.         player->number,
  935.         RD, player->ship,
  936.         RD, player->team_name,
  937.         RD, player->ping,
  938.         RD, player->score,
  939.         RD, player->frags,
  940.         RD, xform_name( player->name, server)
  941.         );
  942.     fputs( "\n", OF);
  943.   }
  944. }
  945.  
  946. void
  947. raw_display_descent3_player_info( struct qserver *server)
  948. {
  949.     static char fmt[28]= "%s" "%s%d" "%s%d" "%s%d" "%s%d";
  950.     struct player *player;
  951.  
  952.     player= server->players;
  953.     for ( ; player != NULL; player= player->next)  {
  954.     fprintf( OF, fmt,
  955.         xform_name( player->name, server),
  956.         RD, player->frags,
  957.         RD, player->deaths,
  958.         RD, player->ping,
  959.         RD, player->team
  960.     );
  961.     fputs( "\n", OF);
  962.     }
  963. }
  964.  
  965.  
  966.  
  967. /* XML output
  968.  * Contributed by <sgarner@gameplanet.co.nz> :-)
  969.  */
  970.  
  971. void
  972. xml_display_server( struct qserver *server)
  973. {
  974.     char *prefix;
  975.     int server_type= server->type->id;
  976.     prefix= server->type->type_prefix;
  977.  
  978.     if ( server->server_name == DOWN)
  979.     {
  980.         if ( ! up_servers_only)
  981.         {
  982.             fprintf( OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\">\n",
  983.                 xml_escape(prefix), xml_escape(server->arg), xml_escape(DOWN));
  984.             fprintf( OF, "\t\t<hostname>%s</hostname>\n",
  985.                 xml_escape((hostname_lookup)?server->host_name:server->arg));
  986.             fprintf( OF, "\t</server>\n");
  987.         }
  988.         return;
  989.     }
  990.     if ( server->server_name == TIMEOUT)
  991.     {
  992.         if ( server->flags & FLAG_BROADCAST && server->n_servers)
  993.         {
  994.             fprintf( OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\" servers=\"%d\">\n",
  995.                 xml_escape(prefix), xml_escape(server->arg),
  996.                 xml_escape(TIMEOUT), server->n_servers);
  997.             fprintf( OF, "\t</server>\n");
  998.         }
  999.         else if ( ! up_servers_only)
  1000.         {
  1001.             fprintf( OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\">\n",
  1002.                 xml_escape(prefix), xml_escape(server->arg), xml_escape(TIMEOUT));
  1003.             fprintf( OF, "\t\t<hostname>%s</hostname>\n",
  1004.                 xml_escape((hostname_lookup)?server->host_name:server->arg));
  1005.             fprintf( OF, "\t</server>\n");
  1006.         }
  1007.         return;
  1008.     }
  1009.  
  1010.     if ( server->error != NULL)
  1011.     {
  1012.         fprintf( OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\">\n",
  1013.             xml_escape(prefix), xml_escape(server->arg), "ERROR");
  1014.         fprintf( OF, "\t\t<hostname>%s</hostname>\n",
  1015.             xml_escape((hostname_lookup)?server->host_name:server->arg));
  1016.         fprintf( OF, "\t\t<error>%s</error>\n",
  1017.             xml_escape(server->error));
  1018.     }
  1019.     else if ( server->type->master)
  1020.     {
  1021.         fprintf( OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\" servers=\"%d\">\n",
  1022.             xml_escape(prefix), xml_escape(server->arg), "UP", server->n_servers);
  1023.     }
  1024.     else  {
  1025.         fprintf( OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\">\n",
  1026.             xml_escape(prefix), xml_escape(server->arg), "UP");
  1027.         fprintf( OF, "\t\t<hostname>%s</hostname>\n",
  1028.             xml_escape((hostname_lookup)?server->host_name:server->arg));
  1029.         fprintf( OF, "\t\t<name>%s</name>\n",
  1030.             xml_escape(xform_name( server->server_name, server)));
  1031.         fprintf( OF, "\t\t<gametype>%s</gametype>\n",
  1032.             xml_escape(get_qw_game(server)));
  1033.         fprintf( OF, "\t\t<map>%s</map>\n",
  1034.             xml_escape(server->map_name));
  1035.         fprintf( OF, "\t\t<numplayers>%d</numplayers>\n",
  1036.             server->num_players);
  1037.         fprintf( OF, "\t\t<maxplayers>%d</maxplayers>\n",
  1038.             server->max_players);
  1039.         
  1040.         if ( server->type->flags & TF_RAW_STYLE_TRIBES)
  1041.         {
  1042.             fprintf( OF, "\t\t<ping>%d</ping>\n",
  1043.                 server->ping_total/server->n_requests);
  1044.             fprintf( OF, "\t\t<retries>%d</retries>\n",
  1045.                 server->n_retries);
  1046.         }
  1047.         
  1048.         if ( server->type->flags & TF_RAW_STYLE_QUAKE)
  1049.         {
  1050.             fprintf( OF, "\t\t<address>%s</address>\n",
  1051.                 xml_escape(server->address));
  1052.             fprintf( OF, "\t\t<protocolversion>%d</protocolversion>\n",
  1053.                 server->protocol_version);
  1054.         }
  1055.     }
  1056.  
  1057.     if ( ! server->type->master && server->error == NULL)
  1058.     {
  1059.         if ( get_server_rules)
  1060.             server->type->display_xml_rule_func( server);
  1061.         if ( get_player_info)
  1062.             server->type->display_xml_player_func( server);
  1063.     }
  1064.  
  1065.     fprintf( OF, "\t</server>\n");
  1066. }
  1067.  
  1068. void
  1069. xml_header()
  1070. {
  1071.     fprintf( OF, "<?xml version=\"1.0\" encoding=\"%s\"?>\n<qstat>\n",
  1072.         xml_encoding == ENCODING_LATIN_1 ? "iso-8859-1" : "UTF-8");
  1073. }
  1074.  
  1075. void
  1076. xml_footer()
  1077. {
  1078.     fprintf( OF, "</qstat>\n");
  1079. }
  1080.  
  1081. void
  1082. xml_display_server_rules( struct qserver *server)
  1083. {
  1084.     struct rule *rule;
  1085.     rule= server->rules;
  1086.     
  1087.     fprintf( OF, "\t\t<rules>\n");
  1088.     for ( ; rule != NULL; rule= rule->next)
  1089.     {
  1090.         fprintf( OF, "\t\t\t<rule name=\"%s\">%s</rule>\n",
  1091.             xml_escape(rule->name), xml_escape(rule->value));
  1092.     }
  1093.     fprintf( OF, "\t\t</rules>\n");
  1094. }
  1095.  
  1096. void
  1097. xml_display_q_player_info( struct qserver *server)
  1098. {
  1099.     struct player *player;
  1100.     
  1101.     fprintf( OF, "\t\t<players>\n");
  1102.  
  1103.     player= server->players;
  1104.     for ( ; player != NULL; player= player->next)
  1105.     {
  1106.         fprintf( OF, "\t\t\t<player number=\"%d\">\n",
  1107.             player->number);
  1108.         
  1109.         fprintf( OF, "\t\t\t\t<name>%s</name>\n",
  1110.             xml_escape(xform_name( player->name, server)));
  1111.         fprintf( OF, "\t\t\t\t<address>%s</address>\n",
  1112.             xml_escape(player->address));
  1113.         fprintf( OF, "\t\t\t\t<score>%d</score>\n",
  1114.             player->frags);
  1115.         fprintf( OF, "\t\t\t\t<time>%s</time>\n",
  1116.             xml_escape(play_time(player->connect_time,1)));
  1117.         
  1118.         if ( color_names)
  1119.         {
  1120.             fprintf( OF, "\t\t\t\t<color for=\"shirt\">%s</color>\n",
  1121.                 xml_escape(quake_color(player->shirt_color)));
  1122.             fprintf( OF, "\t\t\t\t<color for=\"pants\">%s</color>\n",
  1123.                 xml_escape(quake_color(player->pants_color)));
  1124.         }
  1125.         else
  1126.         {
  1127.             fprintf( OF, "\t\t\t\t<color for=\"shirt\">%d</color>\n",
  1128.                 quake_color(player->shirt_color));
  1129.             fprintf( OF, "\t\t\t\t<color for=\"pants\">%d</color>\n",
  1130.                 quake_color(player->pants_color));
  1131.         }
  1132.         
  1133.         fprintf( OF, "\t\t\t</player>\n");
  1134.     }
  1135.     
  1136.     fprintf( OF, "\t\t</players>\n");
  1137. }
  1138.  
  1139. void
  1140. xml_display_qw_player_info( struct qserver *server)
  1141. {
  1142.     struct player *player;
  1143.     
  1144.     fprintf( OF, "\t\t<players>\n");
  1145.  
  1146.     player= server->players;
  1147.     for ( ; player != NULL; player= player->next)
  1148.     {
  1149.         fprintf( OF, "\t\t\t<player number=\"%d\">\n",
  1150.             player->number);
  1151.         
  1152.         fprintf( OF, "\t\t\t\t<name>%s</name>\n",
  1153.             xml_escape(xform_name( player->name, server)));
  1154.         fprintf( OF, "\t\t\t\t<score>%d</score>\n",
  1155.             player->frags);
  1156.         fprintf( OF, "\t\t\t\t<time>%s</time>\n",
  1157.             xml_escape(play_time(player->connect_time,1)));
  1158.         
  1159.         if ( color_names)
  1160.         {
  1161.             fprintf( OF, "\t\t\t\t<color for=\"shirt\">%s</color>\n",
  1162.                 xml_escape(quake_color(player->shirt_color)));
  1163.             fprintf( OF, "\t\t\t\t<color for=\"pants\">%s</color>\n",
  1164.                 xml_escape(quake_color(player->pants_color)));
  1165.         }
  1166.         else
  1167.         {
  1168.             fprintf( OF, "\t\t\t\t<color for=\"shirt\">%d</color>\n",
  1169.                 quake_color(player->shirt_color));
  1170.             fprintf( OF, "\t\t\t\t<color for=\"pants\">%d</color>\n",
  1171.                 quake_color(player->pants_color));
  1172.         }
  1173.         
  1174.         fprintf( OF, "\t\t\t\t<ping>%d</ping>\n",
  1175.             player->ping);
  1176.         fprintf( OF, "\t\t\t\t<skin>%s</skin>\n",
  1177.             player->skin ? xml_escape(player->skin) : "");
  1178.         
  1179.         fprintf( OF, "\t\t\t</player>\n");
  1180.     }
  1181.     
  1182.     fprintf( OF, "\t\t</players>\n");
  1183. }
  1184.  
  1185. void
  1186. xml_display_q2_player_info( struct qserver *server)
  1187. {
  1188.     struct player *player;
  1189.  
  1190.     fprintf( OF, "\t\t<players>\n");
  1191.  
  1192.     player= server->players;
  1193.     for ( ; player != NULL; player= player->next)
  1194.     {
  1195.         fprintf( OF, "\t\t\t<player>\n");
  1196.         
  1197.         fprintf( OF, "\t\t\t\t<name>%s</name>\n",
  1198.             xml_escape(xform_name( player->name, server)));
  1199.         fprintf( OF, "\t\t\t\t<score>%d</score>\n", player->frags);
  1200.         if ( server->flags & FLAG_PLAYER_TEAMS)
  1201.             fprintf( OF, "\t\t\t\t<team>%d</team>\n", player->team);
  1202.         fprintf( OF, "\t\t\t\t<ping>%d</ping>\n",
  1203.             player->ping);
  1204.         
  1205.         fprintf( OF, "\t\t\t</player>\n");
  1206.     }
  1207.     
  1208.     fprintf( OF, "\t\t</players>\n");
  1209. }
  1210.  
  1211. void
  1212. xml_display_unreal_player_info( struct qserver *server)
  1213. {
  1214.     struct player *player;
  1215.     
  1216.     fprintf( OF, "\t\t<players>\n");
  1217.  
  1218.     player= server->players;
  1219.     for ( ; player != NULL; player= player->next)
  1220.     {
  1221.         fprintf( OF, "\t\t\t<player>\n");
  1222.         
  1223.         fprintf( OF, "\t\t\t\t<name>%s</name>\n",
  1224.             xml_escape(xform_name( player->name, server)));
  1225.         fprintf( OF, "\t\t\t\t<score>%d</score>\n",
  1226.             player->frags);
  1227.         fprintf( OF, "\t\t\t\t<ping>%d</ping>\n",
  1228.             player->ping);
  1229.         fprintf( OF, "\t\t\t\t<team>%d</team>\n",
  1230.             player->team);
  1231.         fprintf( OF, "\t\t\t\t<skin>%s</skin>\n",
  1232.             player->skin ? xml_escape(player->skin) : "");
  1233.         fprintf( OF, "\t\t\t\t<mesh>%s</mesh>\n",
  1234.             player->mesh ? xml_escape(player->mesh) : "");
  1235.         fprintf( OF, "\t\t\t\t<face>%s</face>\n",
  1236.             player->face ? xml_escape(player->face) : "");
  1237.         
  1238.         fprintf( OF, "\t\t\t</player>\n");
  1239.     }
  1240.     
  1241.     fprintf( OF, "\t\t</players>\n");
  1242. }
  1243.  
  1244. void
  1245. xml_display_halflife_player_info( struct qserver *server)
  1246. {
  1247.     struct player *player;
  1248.  
  1249.     fprintf( OF, "\t\t<players>\n");
  1250.  
  1251.     player= server->players;
  1252.     for ( ; player != NULL; player= player->next)
  1253.     {
  1254.         fprintf( OF, "\t\t\t<player>\n");
  1255.         
  1256.         fprintf( OF, "\t\t\t\t<name>%s</name>\n",
  1257.             xml_escape(xform_name( player->name, server)));
  1258.         fprintf( OF, "\t\t\t\t<score>%d</score>\n",
  1259.             player->frags);
  1260.         fprintf( OF, "\t\t\t\t<time>%s</time>\n",
  1261.             xml_escape(play_time( player->connect_time,1)));
  1262.         
  1263.         fprintf( OF, "\t\t\t</player>\n");
  1264.     }
  1265.     
  1266.     fprintf( OF, "\t\t</players>\n");
  1267. }
  1268.  
  1269. void
  1270. xml_display_tribes_player_info( struct qserver *server)
  1271. {
  1272.     struct player *player;
  1273.  
  1274.     fprintf( OF, "\t\t<players>\n");
  1275.  
  1276.     player= server->players;
  1277.     for ( ; player != NULL; player= player->next)
  1278.     {
  1279.         fprintf( OF, "\t\t\t<player>\n");
  1280.         
  1281.         fprintf( OF, "\t\t\t\t<name>%s</name>\n",
  1282.             xml_escape(xform_name( player->name, server)));
  1283.         fprintf( OF, "\t\t\t\t<score>%d</score>\n",
  1284.             player->frags);
  1285.         fprintf( OF, "\t\t\t\t<team>%d</team>\n",
  1286.             player->team);
  1287.         fprintf( OF, "\t\t\t\t<ping>%d</ping>\n",
  1288.             player->ping);
  1289.         fprintf( OF, "\t\t\t\t<packetloss>%d</packetloss>\n",
  1290.             player->packet_loss);
  1291.         
  1292.         fprintf( OF, "\t\t\t</player>\n");
  1293.     }
  1294.     
  1295.     fprintf( OF, "\t\t</players>\n");
  1296. }
  1297.  
  1298. void
  1299. xml_display_tribes2_player_info( struct qserver *server)
  1300. {
  1301.     static char fmt[]= "%s" "%s%d" "%s%d" "%s%s" "%s%s" "%s%s";
  1302.     struct player *player;
  1303.     char *type;
  1304.     
  1305.     fprintf( OF, "\t\t<players>\n");
  1306.     
  1307.     player= server->players;
  1308.     for ( ; player != NULL; player= player->next)
  1309.     {
  1310.         if ( player->team_name)
  1311.         {
  1312.             switch( player->type_flag)
  1313.             {
  1314.                 case PLAYER_TYPE_BOT:
  1315.                     type= "Bot";
  1316.                     break;
  1317.                 case PLAYER_TYPE_ALIAS:
  1318.                     type= "Alias";
  1319.                     break;
  1320.                 default:
  1321.                     type= "";
  1322.                     break;
  1323.             }
  1324.             
  1325.             fprintf( OF, "\t\t\t<player>\n");
  1326.             
  1327.             fprintf( OF, "\t\t\t\t<name>%s</name>\n",
  1328.                 xml_escape(xform_name( player->name, server)));
  1329.             fprintf( OF, "\t\t\t\t<score>%d</score>\n",
  1330.                 player->frags);
  1331.             fprintf( OF, "\t\t\t\t<team number=\"%d\">%s</team>\n",
  1332.                 player->team, xml_escape(player->team_name));
  1333.             fprintf( OF, "\t\t\t\t<type>%s</type>\n",
  1334.                 xml_escape(type));
  1335.             fprintf( OF, "\t\t\t\t<clan>%s</clan>\n",
  1336.                 player->tribe_tag ? xml_escape(xform_name(player->tribe_tag,server)) : "");
  1337.             
  1338.             fprintf( OF, "\t\t\t</player>\n");
  1339.         }
  1340.     }
  1341.     
  1342.     fprintf( OF, "\t\t</players>\n");
  1343. }
  1344.  
  1345. void
  1346. xml_display_bfris_player_info( struct qserver *server)
  1347. {
  1348.     struct player *player;
  1349.     
  1350.     fprintf( OF, "\t\t<players>\n");
  1351.     
  1352.     player= server->players;
  1353.     for ( ; player != NULL; player= player->next)
  1354.     {
  1355.         fprintf( OF, "\t\t\t<player number=\"%d\">\n",
  1356.             player->number);
  1357.         
  1358.         fprintf( OF, "\t\t\t\t<name>%s</name>\n",
  1359.             xml_escape(xform_name( player->name, server)));
  1360.         fprintf( OF, "\t\t\t\t<score type=\"score\">%d</score>\n",
  1361.             player->score);
  1362.         fprintf( OF, "\t\t\t\t<score type=\"frags\">%d</score>\n",
  1363.             player->frags);
  1364.         fprintf( OF, "\t\t\t\t<team>%s</team>\n",
  1365.             xml_escape(player->team_name));
  1366.         fprintf( OF, "\t\t\t\t<ping>%d</ping>\n",
  1367.             player->ping);
  1368.         fprintf( OF, "\t\t\t\t<ship>%d</ship>\n",
  1369.             player->ship);
  1370.         
  1371.         fprintf( OF, "\t\t\t</player>\n");
  1372.     }
  1373.     
  1374.     fprintf( OF, "\t\t</players>\n");
  1375. }
  1376.  
  1377. void
  1378. xml_display_descent3_player_info( struct qserver *server)
  1379. {
  1380.     struct player *player;
  1381.     
  1382.     fprintf( OF, "\t\t<players>\n");
  1383.  
  1384.     player= server->players;
  1385.     for ( ; player != NULL; player= player->next)
  1386.     {
  1387.         fprintf( OF, "\t\t\t<player>\n");
  1388.         
  1389.         fprintf( OF, "\t\t\t\t<name>%s</name>\n",
  1390.             xml_escape(xform_name( player->name, server)));
  1391.         fprintf( OF, "\t\t\t\t<score>%d</score>\n",
  1392.             player->frags);
  1393.         fprintf( OF, "\t\t\t\t<deaths>%d</deaths>\n",
  1394.             player->deaths);
  1395.         fprintf( OF, "\t\t\t\t<ping>%d</ping>\n",
  1396.             player->ping);
  1397.         fprintf( OF, "\t\t\t\t<team>%d</team>\n",
  1398.             player->team);
  1399.         
  1400.         fprintf( OF, "\t\t\t</player>\n");
  1401.     }
  1402.     
  1403.     fprintf( OF, "\t\t</players>\n");
  1404. }
  1405.  
  1406.  
  1407. void
  1408. display_progress()
  1409. {
  1410.     fprintf( stderr, "\r%d/%d (%d timed out, %d down)",
  1411.     num_servers_returned+num_servers_timed_out,
  1412.     num_servers_total,
  1413.     num_servers_timed_out,
  1414.     num_servers_down);
  1415. }
  1416.  
  1417. /* ----- END MODIFICATION ----- Don't need to change anything below here. */
  1418.  
  1419.  
  1420. void set_non_blocking( int fd);
  1421. int set_fds( fd_set *fds);
  1422. void get_next_timeout( struct timeval *timeout);
  1423.  
  1424. void set_file_descriptors();
  1425. int wait_for_file_descriptors( struct timeval *timeout);
  1426. struct qserver * get_next_ready_server();
  1427.  
  1428.  
  1429. /* Misc flags
  1430.  */
  1431.  
  1432. char * NO_SERVER_RULES= NULL;
  1433. int NO_PLAYER_INFO= 0xffff;
  1434. struct timeval packet_recv_time;
  1435. int one_server_type_id= ~ MASTER_SERVER;
  1436. static int one= 1;
  1437. static int little_endian;
  1438. static int big_endian;
  1439. unsigned int swap_long( void *);
  1440. unsigned short swap_short( void *);
  1441. unsigned int swap_long_from_little( void *l);
  1442. unsigned short swap_short_from_little( void *l);
  1443. char * strndup( char *string, int len);
  1444. #define FORCE 1
  1445.  
  1446. /* Print an error message and the program usage notes
  1447.  */
  1448.  
  1449. void
  1450. usage( char *msg, char **argv, char *a1)
  1451. {
  1452.     server_type *type;
  1453.  
  1454.     if ( msg)
  1455.     fprintf( stderr, msg, a1);
  1456.  
  1457.     printf( "Usage: %s [options ...]\n", argv[0]);
  1458.     printf( "\t[-default server-type] [-f file] [host[:port]] ...\n");
  1459.     printf( "Where host is an IP address or host name\n");
  1460.     type= &types[0];
  1461.     for ( ; type->id != Q_UNKNOWN_TYPE; type++)
  1462.     printf( "%s\t\tquery %s server\n", type->type_option,
  1463.         type->game_name);
  1464.     printf( "-default\tset default server type:");
  1465.     type= &types[0];
  1466.     for ( ; type->id != Q_UNKNOWN_TYPE; type++)
  1467.     printf( " %s", type->type_string);
  1468.     puts("");
  1469.     printf( "-f\t\tread hosts from file\n");
  1470.     printf( "-R\t\tfetch and display server rules\n");
  1471.     printf( "-P\t\tfetch and display player info\n");
  1472.     printf( "-sort\t\tsort servers and/or players\n");
  1473.     printf( "-u\t\tonly display servers that are up\n");
  1474.     printf( "-nf\t\tdo not display full servers\n");
  1475.     printf( "-ne\t\tdo not display empty servers\n");
  1476.     printf( "-cn\t\tdisplay color names instead of numbers\n");
  1477.     printf( "-ncn\t\tdisplay color numbers instead of names\n");
  1478.     printf( "-hc\t\tdisplay colors in #rrggbb format\n");
  1479.     printf( "-tc\t\tdisplay time in clock format (DhDDmDDs)\n");
  1480.     printf( "-tsw\t\tdisplay time in stop-watch format (DD:DD:DD)\n");
  1481.     printf( "-ts\t\tdisplay time in seconds\n");
  1482.     printf( "-pa\t\tdisplay player address\n");
  1483.     printf( "-hpn\t\tdisplay player names in hex\n");
  1484.     printf( "-nh\t\tdo not display header\n");
  1485.     printf( "-old\t\told style display\n");
  1486.     printf( "-progress\tdisplay progress meter (text only)\n");
  1487.     printf( "-retry\t\tnumber of retries, default is %d\n", DEFAULT_RETRIES);
  1488.     printf( "-interval\tinterval between retries, default is %.2lf seconds\n",
  1489.     DEFAULT_RETRY_INTERVAL / 1000.0);
  1490.     printf( "-mi\t\tinterval between master server retries, default is %.2lf seconds\n",
  1491.     (DEFAULT_RETRY_INTERVAL*4) / 1000.0);
  1492.     printf( "-timeout\ttotal time in seconds before giving up\n");
  1493.     printf( "-maxsim\t\tset maximum simultaneous queries\n");
  1494.     printf( "-errors\t\tdisplay errors\n");
  1495.     printf( "-of\t\toutput file\n");
  1496.     printf( "-raw <delim>\toutput in raw format using <delim> as delimiter\n");
  1497.     printf( "-xml\t\toutput status data as an XML document\n");
  1498.     printf( "-Th,-Ts,-Tp,-Tr,-Tt\toutput templates: header, server, player, rule, and trailer\n");
  1499.     printf( "-srcport <range>\tSend packets from these network ports\n");
  1500.     printf( "-srcip <IP>\tSend packets using this IP address\n");
  1501.     printf( "-H\t\tresolve host names\n");
  1502.     printf( "-Hcache\t\thost name cache file\n");
  1503.     printf( "\n");
  1504.     printf( "Sort keys:\n");
  1505.     printf( "  servers: p=by-ping, g=by-game, i=by-IP-address, h=by-hostname, n=by-#-players, l=by-list-order\n");
  1506.     printf( "  players: P=by-ping, F=by-frags, T=by-team\n");
  1507.     printf( "\nqstat version %s\n", VERSION);
  1508.     exit(0);
  1509. }
  1510.  
  1511. struct server_arg  {
  1512.     int type_id;
  1513.     server_type *type;
  1514.     char *arg;
  1515.     char *outfilename;
  1516.     char *query_arg;
  1517. };
  1518.  
  1519. server_type*
  1520. find_server_type_id( int type_id)
  1521. {
  1522.     server_type *type= &types[0];
  1523.     for ( ; type->id != Q_UNKNOWN_TYPE; type++)
  1524.     if ( type->id == type_id)
  1525.         return type;
  1526.     return NULL;
  1527. }
  1528.  
  1529. server_type*
  1530. find_server_type_string( char* type_string)
  1531. {
  1532.     server_type *type= &types[0];
  1533.     char *t= type_string;
  1534.     while ( *t) *t++= tolower( *t);
  1535.  
  1536.     for ( ; type->id != Q_UNKNOWN_TYPE; type++)
  1537.     if ( strcmp( type->type_string, type_string) == 0)
  1538.         return type;
  1539.     return NULL;
  1540. }
  1541.  
  1542. server_type*
  1543. find_server_type_option( char* option)
  1544. {
  1545.     server_type *type= &types[0];
  1546.     for ( ; type->id != Q_UNKNOWN_TYPE; type++)
  1547.     if ( strcmp( type->type_option, option) == 0)
  1548.         return type;
  1549.     return NULL;
  1550. }
  1551.  
  1552. server_type*
  1553. parse_server_type_option( char* option, int *outfile, char **query_arg)
  1554. {
  1555.     server_type *type= &types[0];
  1556.     char *comma, *arg;
  1557.     int len;
  1558.  
  1559.     *outfile= 0;
  1560.     *query_arg= 0;
  1561.  
  1562.     comma= strchr( option, ',');
  1563.     if ( comma)
  1564.     *comma++= '\0';
  1565.  
  1566.     for ( ; type->id != Q_UNKNOWN_TYPE; type++)
  1567.     if ( strcmp( type->type_option, option) == 0)
  1568.         break;
  1569.  
  1570.     if ( type->id == Q_UNKNOWN_TYPE)
  1571.     return NULL;
  1572.  
  1573.     if ( ! comma)
  1574.     return type;
  1575.  
  1576.     if ( strcmp( comma, "outfile") == 0)  {
  1577.     *outfile= 1;
  1578.     comma= strchr( comma, ',');
  1579.     if ( ! comma)
  1580.         return type;
  1581.     *comma++= '\0';
  1582.     }
  1583.  
  1584.     *query_arg= comma;
  1585.     arg= *query_arg;
  1586.     do  {
  1587.     comma= strchr( arg, ',');
  1588.     if (comma)
  1589.         len= comma-arg;
  1590.     else
  1591.         len= strlen( arg);
  1592.     if ( strncmp( arg, "outfile", len) == 0)
  1593.         *outfile= 1;
  1594.     arg= comma+1;
  1595.     } while ( comma);
  1596.     return type;
  1597. }
  1598.  
  1599. void
  1600. add_server_arg( char *arg, int type, char *outfilename, char *query_arg,
  1601.     struct server_arg **args, int *n, int *max)
  1602. {
  1603.     if ( *n == *max)  {
  1604.     if ( *max == 0)  {
  1605.         *max= 4;
  1606.         *args= (struct server_arg*)malloc(sizeof(struct server_arg) * (*max));
  1607.     }
  1608.     else  {
  1609.         (*max)*= 2;
  1610.         *args= (struct server_arg*) realloc( *args,
  1611.         sizeof(struct server_arg) * (*max));
  1612.     }
  1613.     }
  1614.     (*args)[*n].type_id= type;
  1615. /*    (*args)[*n].type= find_server_type_id( type); */
  1616.     (*args)[*n].type= NULL;
  1617.     (*args)[*n].arg= arg;
  1618.     (*args)[*n].outfilename= outfilename;
  1619.     (*args)[*n].query_arg= query_arg;
  1620.     (*n)++;
  1621. }
  1622.  
  1623.  
  1624. void
  1625. add_query_param( struct qserver *server, char *arg)
  1626. {
  1627.     char *equal;
  1628.     struct query_param *param;
  1629.  
  1630.     equal= strchr( arg, '=');
  1631.     *equal++= '\0';
  1632.  
  1633.     param= (struct query_param *) malloc( sizeof(struct query_param));
  1634.     param->key= arg;
  1635.     param->value= equal;
  1636.     sscanf( equal, "%i", ¶m->i_value);
  1637.     sscanf( equal, "%i", ¶m->ui_value);
  1638.     param->next= server->params;
  1639.     server->params= param;
  1640. }
  1641.  
  1642. char *
  1643. get_param_value( struct qserver *server, char *key, char *default_value)
  1644. {
  1645.     struct query_param *p= server->params;
  1646.     for ( ; p; p= p->next)
  1647.     if ( strcasecmp( key, p->key) == 0)
  1648.         return p->value;
  1649.     return default_value;
  1650. }
  1651.  
  1652. int
  1653. get_param_i_value( struct qserver *server, char *key, int default_value)
  1654. {
  1655.     struct query_param *p= server->params;
  1656.     for ( ; p; p= p->next)
  1657.     if ( strcasecmp( key, p->key) == 0)
  1658.         return p->i_value;
  1659.     return default_value;
  1660. }
  1661.  
  1662. unsigned int
  1663. get_param_ui_value( struct qserver *server, char *key,
  1664.     unsigned int default_value)
  1665. {
  1666.     struct query_param *p= server->params;
  1667.     for ( ; p; p= p->next)
  1668.     if ( strcasecmp( key, p->key) == 0)
  1669.         return p->ui_value;
  1670.     return default_value;
  1671. }
  1672.  
  1673. int
  1674. parse_source_address( char *addr, unsigned int *ip, unsigned short *port)
  1675. {
  1676.     char *colon;
  1677.     colon= strchr( addr, ':');
  1678.     if ( colon)  {
  1679.     *colon= '\0';
  1680.     *port= atoi( colon+1);
  1681.     if ( colon == addr)
  1682.         return 0;
  1683.     }
  1684.     else
  1685.     *port= 0;
  1686.  
  1687.     *ip= inet_addr( addr);
  1688.     if ( *ip == INADDR_NONE && !isdigit( *ip))
  1689.     *ip= hcache_lookup_hostname( addr);
  1690.     if ( *ip == INADDR_NONE)  {
  1691.     fprintf( stderr, "%s: Not an IP address or unknown host name\n", addr);
  1692.     return -1;
  1693.     }
  1694.     *ip= ntohl( *ip);
  1695.     return 0;
  1696. }
  1697.  
  1698. int
  1699. parse_source_port( char *port, unsigned short *low, unsigned short *high)
  1700. {
  1701.     char *dash;
  1702.     *low= atoi( port);
  1703.     dash= strchr( port, '-');
  1704.     *high= 0;
  1705.     if ( dash)
  1706.     *high= atoi( dash+1);
  1707.     if ( *high == 0)
  1708.     *high= *low;
  1709.  
  1710.     if ( *high < *low)  {
  1711.     fprintf( stderr, "%s: Invalid port range\n", port);
  1712.     return -1;
  1713.     }
  1714.     return 0;
  1715. }
  1716.  
  1717. void
  1718. add_config_server_types()
  1719. {
  1720.     int n_config_types, n_builtin_types, i;
  1721.     server_type **config_types;
  1722.     server_type *new_types, *type;
  1723.     config_types= qsc_get_config_server_types( &n_config_types);
  1724.  
  1725.     if ( n_config_types == 0)
  1726.     return;
  1727.  
  1728.     n_builtin_types= (sizeof( builtin_types) / sizeof(server_type)) - 1;
  1729.     new_types= (server_type*) malloc( sizeof(server_type) * (n_builtin_types +
  1730.         n_config_types + 1));
  1731.  
  1732.     memcpy( new_types, &builtin_types[0], n_builtin_types*sizeof(server_type));
  1733.     type= &new_types[n_builtin_types];
  1734.     for ( i= n_config_types; i; i--, config_types++, type++)
  1735.     *type= **config_types;
  1736.     n_server_types= n_builtin_types + n_config_types;
  1737.     new_types[n_server_types].id= Q_UNKNOWN_TYPE;
  1738.     if ( types != &builtin_types[0])
  1739.     free( types);
  1740.     types= new_types;
  1741. }
  1742.  
  1743. void
  1744. revert_server_types()
  1745. {
  1746.     if ( types != &builtin_types[0])
  1747.     free( types);
  1748.     n_server_types= (sizeof( builtin_types) / sizeof(server_type)) - 1;
  1749.     types= &builtin_types[0];
  1750. }
  1751.  
  1752.  
  1753. main( int argc, char *argv[])
  1754. {
  1755.     int pktlen, rc, fd;
  1756.     long pkt_data[PACKET_LEN/sizeof(long)];
  1757.     char *pkt= (char*)&pkt_data[0];
  1758.     struct timeval timeout;
  1759.     int arg, n_files, i;
  1760.     struct qserver *server;
  1761.     char **files, *outfilename, *query_arg;
  1762.     struct server_arg *server_args= NULL;
  1763.     int n_server_args= 0, max_server_args= 0;
  1764.     int show_recv_packets= 0;
  1765.     int bind_retry= 0;
  1766.     int default_server_type_id;
  1767.  
  1768. #ifdef _WIN32
  1769.     WORD version= MAKEWORD(1,1);
  1770.     WSADATA wsa_data;
  1771.     if ( WSAStartup(version,&wsa_data) != 0)  {
  1772.     fprintf( stderr, "Could not open winsock\n");
  1773.     exit(1);
  1774.     }
  1775. #endif
  1776.  
  1777.     types= &builtin_types[0];
  1778.     n_server_types= (sizeof( builtin_types) / sizeof(server_type)) - 1;
  1779.  
  1780.     i= qsc_load_default_config_files();
  1781.     if ( i == -1)
  1782.     return 1;
  1783.     else if ( i == 0)
  1784.     add_config_server_types();
  1785.  
  1786.     if ( argc == 1)
  1787.     usage(NULL,argv,NULL);
  1788.  
  1789.     OF= stdout;
  1790.  
  1791.     files= (char **) malloc( sizeof(char*) * (argc/2));
  1792.     n_files= 0;
  1793.  
  1794.     default_server_type_id= Q_SERVER;
  1795.     little_endian= ((char*)&one)[0];
  1796.     big_endian= !little_endian;
  1797.  
  1798.     for ( arg= 1; arg < argc; arg++)  {
  1799.     if ( argv[arg][0] != '-')
  1800.         break;
  1801.     outfilename= NULL;
  1802.     if ( strcmp( argv[arg], "-nocfg") == 0 && arg == 1)  {
  1803.         revert_server_types();
  1804.     }
  1805.     else if ( strcmp( argv[arg], "-f") == 0)  {
  1806.         arg++;
  1807.         if ( arg >= argc)
  1808.         usage( "missing argument for -f\n", argv,NULL);
  1809.         files[n_files++]= argv[arg];
  1810.     }
  1811.     else if ( strcmp( argv[arg], "-retry") == 0)  {
  1812.         arg++;
  1813.         if ( arg >= argc)
  1814.         usage( "missing argument for -retry\n", argv,NULL);
  1815.         n_retries= atoi( argv[arg]);
  1816.         if ( n_retries <= 0)  {
  1817.         fprintf( stderr, "retries must be greater than zero\n");
  1818.         exit(1);
  1819.         }
  1820.     }
  1821.     else if ( strcmp( argv[arg], "-interval") == 0)  {
  1822.         double value= 0.0;
  1823.         arg++;
  1824.         if ( arg >= argc)
  1825.         usage( "missing argument for -interval\n", argv,NULL);
  1826.         sscanf( argv[arg], "%lf", &value);
  1827.         if ( value < 0.1)  {
  1828.         fprintf( stderr, "retry interval must be greater than 0.1\n");
  1829.         exit(1);
  1830.         }
  1831.         retry_interval= (int)(value * 1000);
  1832.     }
  1833.     else if ( strcmp( argv[arg], "-mi") == 0)  {
  1834.         double value= 0.0;
  1835.         arg++;
  1836.         if ( arg >= argc)
  1837.         usage( "missing argument for -mi\n", argv,NULL);
  1838.         sscanf( argv[arg], "%lf", &value);
  1839.         if ( value < 0.1)  {
  1840.         fprintf( stderr, "interval must be greater than 0.1\n");
  1841.         exit(1);
  1842.         }
  1843.         master_retry_interval= (int)(value * 1000);
  1844.     }
  1845.     else if ( strcmp( argv[arg], "-H") == 0)
  1846.         hostname_lookup= 1;
  1847.     else if ( strcmp( argv[arg], "-u") == 0)
  1848.         up_servers_only= 1;
  1849.     else if ( strcmp( argv[arg], "-nf") == 0)
  1850.         no_full_servers= 1;
  1851.     else if ( strcmp( argv[arg], "-ne") == 0)
  1852.         no_empty_servers= 1;
  1853.     else if ( strcmp( argv[arg], "-nh") == 0)
  1854.         no_header_display= 1;
  1855.     else if ( strcmp( argv[arg], "-old") == 0)
  1856.         new_style= 0;
  1857.     else if ( strcmp( argv[arg], "-P") == 0)
  1858.         get_player_info= 1;
  1859.     else if ( strcmp( argv[arg], "-R") == 0)
  1860.         get_server_rules= 1;
  1861.     else if ( strncmp( argv[arg], "-raw", 4) == 0)  {
  1862.         if ( argv[arg][4] == ',')  {
  1863.         if ( strcmp( &argv[arg][5], "game") == 0)
  1864.             show_game_in_raw= 1;
  1865.         else
  1866.             usage( "Unknown -raw option\n", argv, NULL);
  1867.         }
  1868.         arg++;
  1869.         if ( arg >= argc)
  1870.         usage( "missing argument for -raw\n", argv,NULL);
  1871.         raw_delimiter= argv[arg];
  1872.         raw_display= 1;
  1873.     }
  1874.     else if ( strcmp( argv[arg], "-xml") == 0) {
  1875.         xml_display= 1;
  1876.         if (raw_display == 1)
  1877.         usage( "cannot specify both -raw and -xml\n", argv,NULL);
  1878.     }
  1879.     else if ( strcmp( argv[arg], "-utf8") == 0) {
  1880.         xml_encoding= ENCODING_UTF_8;
  1881.     }
  1882.     else if ( strcmp( argv[arg], "-ncn") == 0)  {
  1883.         color_names= 0;
  1884.      }
  1885.     else if ( strcmp( argv[arg], "-cn") == 0)  {
  1886.         color_names= 1;
  1887.      }
  1888.     else if ( strcmp( argv[arg], "-hc") == 0)  {
  1889.         color_names= 2;
  1890.      }
  1891.     else if ( strcmp( argv[arg], "-tc") == 0)  {
  1892.         time_format= CLOCK_TIME;
  1893.     }
  1894.     else if ( strcmp( argv[arg], "-tsw") == 0)  {
  1895.         time_format= STOPWATCH_TIME;
  1896.     }
  1897.     else if ( strcmp( argv[arg], "-ts") == 0)  {
  1898.         time_format= SECONDS;
  1899.     }
  1900.     else if ( strcmp( argv[arg], "-pa") == 0)  {
  1901.         player_address= 1;
  1902.     }
  1903.     else if ( strcmp( argv[arg], "-hpn") == 0)  {
  1904.         hex_player_names= 1;
  1905.     }
  1906.     else if ( strncmp( argv[arg], "-maxsimultaneous", 7) == 0)  {
  1907.         arg++;
  1908.         if ( arg >= argc)
  1909.         usage( "missing argument for -maxsimultaneous\n", argv,NULL);
  1910.         max_simultaneous= atoi(argv[arg]);
  1911.         if ( max_simultaneous <= 0)
  1912.         usage( "value for -maxsimultaneous must be > 0\n", argv,NULL);
  1913.         if ( max_simultaneous > FD_SETSIZE)
  1914.         max_simultaneous= FD_SETSIZE;
  1915.      }
  1916.     else if ( strcmp( argv[arg], "-raw-arg") == 0)  {
  1917.         raw_arg= 1000;
  1918.      }
  1919.     else if ( strcmp( argv[arg], "-timeout") == 0)  {
  1920.         arg++;
  1921.         if ( arg >= argc)
  1922.         usage( "missing argument for -timeout\n", argv,NULL);
  1923.         run_timeout= atoi( argv[arg]);
  1924.         if ( run_timeout <= 0)
  1925.         usage( "value for -timeout must be > 0\n", argv,NULL);
  1926.     }
  1927.     else if ( strcmp( argv[arg], "-progress") == 0)  {
  1928.         progress= 1;
  1929.      }
  1930.     else if ( strcmp( argv[arg], "-Hcache") == 0)  {
  1931.         arg++;
  1932.         if ( arg >= argc)
  1933.         usage( "missing argument for -Hcache\n", argv,NULL);
  1934.         if ( hcache_open( argv[arg], 0) == -1)
  1935.         return 1;
  1936.     }
  1937.     else if ( strcmp( argv[arg], "-default") == 0)  {
  1938.         arg++;
  1939.         if ( arg >= argc)
  1940.         usage( "missing argument for -default\n", argv,NULL);
  1941.         default_server_type= find_server_type_string( argv[arg]);
  1942.         if ( default_server_type == NULL)  {
  1943.         char opt[256], *o= &opt[0];
  1944.         sprintf( opt, "-%s", argv[arg]);
  1945.         while ( *o) *o++= tolower(*o);
  1946.         default_server_type= find_server_type_option( opt);
  1947.         }
  1948.         if ( default_server_type == NULL)  {
  1949.         fprintf( stderr, "unknown server type \"%s\"\n", argv[arg]);
  1950.         usage( NULL, argv,NULL);
  1951.         }
  1952.         default_server_type_id= default_server_type->id;
  1953.         default_server_type= NULL;
  1954.     }
  1955.     else if ( strncmp( argv[arg], "-Tserver", 3) == 0)  {
  1956.         arg++;
  1957.         if ( arg >= argc)
  1958.         usage( "missing argument for %s\n", argv, argv[arg-1]);
  1959.         if ( read_qserver_template( argv[arg]) == -1)
  1960.         return 1;
  1961.     }
  1962.     else if ( strncmp( argv[arg], "-Trule", 3) == 0)  {
  1963.         arg++;
  1964.         if ( arg >= argc)
  1965.         usage( "missing argument for %s\n", argv, argv[arg-1]);
  1966.         if ( read_rule_template( argv[arg]) == -1)
  1967.         return 1;
  1968.     }
  1969.     else if ( strncmp( argv[arg], "-Theader", 3) == 0)  {
  1970.         arg++;
  1971.         if ( arg >= argc)
  1972.         usage( "missing argument for %s\n", argv, argv[arg-1]);
  1973.         if ( read_header_template( argv[arg]) == -1)
  1974.         return 1;
  1975.     }
  1976.     else if ( strncmp( argv[arg], "-Ttrailer", 3) == 0)  {
  1977.         arg++;
  1978.         if ( arg >= argc)
  1979.         usage( "missing argument for %s\n", argv, argv[arg-1]);
  1980.         if ( read_trailer_template( argv[arg]) == -1)
  1981.         return 1;
  1982.     }
  1983.     else if ( strncmp( argv[arg], "-Tplayer", 3) == 0)  {
  1984.         arg++;
  1985.         if ( arg >= argc)
  1986.         usage( "missing argument for %s\n", argv, argv[arg-1]);
  1987.         if ( read_player_template( argv[arg]) == -1)
  1988.         return 1;
  1989.     }
  1990.     else if ( strcmp( argv[arg], "-sort") == 0)  {
  1991.         arg++;
  1992.         if ( arg >= argc)
  1993.         usage( "missing argument for -sort\n", argv, NULL);
  1994.         strncpy( sort_keys, argv[arg], sizeof(sort_keys)-1);
  1995.         rc= strspn( sort_keys, SUPPORTED_SORT_KEYS);
  1996.         if ( rc != strlen( sort_keys))  {
  1997.         fprintf( stderr, "Unknown sort key \"%c\", valid keys are \"%s\"\n",
  1998.             sort_keys[rc], SUPPORTED_SORT_KEYS);
  1999.         return 1;
  2000.         }
  2001.         server_sort= strpbrk( sort_keys, SUPPORTED_SERVER_SORT) != NULL;
  2002.         if ( strchr( sort_keys, 'l'))
  2003.         server_sort= 1;
  2004.         player_sort= strpbrk( sort_keys, SUPPORTED_PLAYER_SORT) != NULL;
  2005.     }
  2006.     else if ( strcmp( argv[arg], "-errors") == 0)  {
  2007.         show_errors++;
  2008.     }
  2009.     else if ( strcmp( argv[arg], "-of") == 0)  {
  2010.         arg++;
  2011.         if ( arg >= argc)
  2012.         usage( "missing argument for %s\n", argv, argv[arg-1]);
  2013.         OF= fopen( argv[arg], "w");
  2014.         if ( OF == NULL)  {
  2015.         perror( argv[arg]);
  2016.         return 1;
  2017.         }
  2018.     }
  2019.     else if ( strcmp( argv[arg], "-af") == 0)  {
  2020.         arg++;
  2021.         if ( arg >= argc)
  2022.         usage( "missing argument for %s\n", argv, argv[arg-1]);
  2023.         OF= fopen( argv[arg], "a");
  2024.         if ( OF == NULL)  {
  2025.         perror( argv[arg]);
  2026.         return 1;
  2027.         }
  2028.     }
  2029.     else if ( strcmp( argv[arg], "-htmlnames") == 0)  {
  2030.         html_names= 1;
  2031.     }
  2032.     else if ( strcmp( argv[arg], "-nohtmlnames") == 0)  {
  2033.         html_names= 0;
  2034.     }
  2035.     else if ( strcmp( argv[arg], "-htmlmode") == 0)  {
  2036.         html_mode= 1;
  2037.     }
  2038.     else if ( strcmp( argv[arg], "-carets") == 0)  {
  2039.         strip_carets= 0;
  2040.     }
  2041.     else if ( strcmp( argv[arg], "-d") == 0)  {
  2042.         show_recv_packets= 1;
  2043.     }
  2044.     else if ( strcmp( argv[arg], "-srcip") == 0)  {
  2045.         arg++;
  2046.         if ( arg >= argc)
  2047.         usage( "missing argument for %s\n", argv, argv[arg-1]);
  2048.         if ( parse_source_address( argv[arg], &source_ip, &source_port) == -1)
  2049.         return 1;
  2050.         if ( source_port)  {
  2051.         source_port_low= source_port;
  2052.         source_port_high= source_port;
  2053.         }
  2054.     }
  2055.     else if ( strcmp( argv[arg], "-srcport") == 0)  {
  2056.         arg++;
  2057.         if ( arg >= argc)
  2058.         usage( "missing argument for %s\n", argv, argv[arg-1]);
  2059.         if ( parse_source_port( argv[arg], &source_port_low, &source_port_high) == -1)
  2060.         return 1;
  2061.         source_port= source_port_low;
  2062.     }
  2063.     else if ( strcmp( argv[arg], "-cfg") == 0)  {
  2064.         arg++;
  2065.         if ( arg >= argc)
  2066.         usage( "missing argument for %s\n", argv, argv[arg-1]);
  2067.         if ( qsc_load_config_file( argv[arg]) == -1)
  2068.         return 1;
  2069.         add_config_server_types();
  2070.     }
  2071. #ifdef _WIN32
  2072.     else if ( strcmp( argv[arg], "-noconsole") == 0)  {
  2073.         FreeConsole();
  2074.     }
  2075. #endif
  2076.     else  {
  2077.         int outfile;
  2078.         server_type *type;
  2079.         arg++;
  2080.         if ( arg >= argc)  {
  2081.         fprintf( stderr, "missing argument for \"%s\"\n", argv[arg-1]);
  2082.         return 1;
  2083.         }
  2084.         type= parse_server_type_option( argv[arg-1], &outfile, &query_arg);
  2085.         if ( type == NULL)  {
  2086.         fprintf( stderr, "unknown option \"%s\"\n", argv[arg-1]);
  2087.         return 1;
  2088.         }
  2089.         outfilename= NULL;
  2090.         if ( outfile)  {
  2091.         outfilename= strchr( argv[arg], ',');
  2092.         if ( outfilename == NULL)  {
  2093.             fprintf( stderr, "missing file name for \"%s,outfile\"\n",
  2094.             argv[arg-1]);
  2095.             return 1;
  2096.         }
  2097.         *outfilename++= '\0';
  2098.         }
  2099.         if ( query_arg && !(type->flags & TF_QUERY_ARG))  {
  2100.         fprintf( stderr, "option flag \"%s\" not allowed for this server type\n",
  2101.             query_arg);
  2102.         return 1;
  2103.         }
  2104.         if ( type->flags & TF_QUERY_ARG_REQUIRED && !query_arg)  {
  2105.         fprintf( stderr, "option flag missing for server type \"%s\"\n",
  2106.             argv[arg-1]);
  2107.         return 1;
  2108.         }
  2109.         add_server_arg( argv[arg], type->id, outfilename, query_arg,
  2110.         &server_args, &n_server_args, &max_server_args);
  2111.     }
  2112.     }
  2113.  
  2114.     start_time= time(0);
  2115.  
  2116.     default_server_type= find_server_type_id( default_server_type_id);
  2117.  
  2118.     for ( i= 0; i < n_files; i++)
  2119.     add_file( files[i]);
  2120.  
  2121.     for ( ; arg < argc; arg++)
  2122.     add_qserver( argv[arg], default_server_type, NULL, NULL);
  2123.  
  2124.     for ( i= 0; i < n_server_args; i++)  {
  2125.     server_type *server_type= find_server_type_id( server_args[i].type_id);
  2126.     add_qserver( server_args[i].arg, server_type,
  2127.         server_args[i].outfilename, server_args[i].query_arg);
  2128.     }
  2129.  
  2130.     free( server_args);
  2131.  
  2132.     if ( servers == NULL)
  2133.     exit(1);
  2134.  
  2135.     max_connmap= max_simultaneous + 10;
  2136.     connmap= (struct qserver**) calloc( 1, sizeof(struct qserver*) * max_connmap);
  2137.  
  2138.     if ( color_names == -1)
  2139.     color_names= ( raw_display) ? DEFAULT_COLOR_NAMES_RAW :
  2140.         DEFAULT_COLOR_NAMES_DISPLAY;
  2141.  
  2142.     if ( time_format == -1)
  2143.     time_format= ( raw_display) ? DEFAULT_TIME_FMT_RAW :
  2144.         DEFAULT_TIME_FMT_DISPLAY;
  2145.  
  2146.     if ( (one_server_type_id & MASTER_SERVER) || one_server_type_id == 0)
  2147.     display_prefix= 1;
  2148.  
  2149.     if ( xml_display)
  2150.     xml_header();
  2151.     else if ( new_style && ! raw_display && ! have_server_template())
  2152.     display_header();
  2153.     else if ( have_header_template())
  2154.     template_display_header();
  2155.  
  2156.     q_serverinfo.length= htons( q_serverinfo.length);
  2157.     h2_serverinfo.length= htons( h2_serverinfo.length);
  2158.     q_player.length= htons( q_player.length);
  2159.  
  2160.     bind_sockets();
  2161.  
  2162.     while ( connected || (!connected && bind_retry==-2))  {
  2163.     int last_connected= connected;
  2164.  
  2165.     if ( ! connected && bind_retry==-2)  {
  2166.         rc= wait_for_timeout( 60);
  2167.         bind_retry= bind_sockets();
  2168.         continue;
  2169.     }
  2170.     bind_retry= 0;
  2171.  
  2172.     set_file_descriptors();
  2173.  
  2174.     if ( progress)
  2175.         display_progress();
  2176.     get_next_timeout( &timeout);
  2177.     
  2178.     rc= wait_for_file_descriptors( &timeout);
  2179.  
  2180.     if ( rc == 0)  {
  2181.         if ( run_timeout && time(0)-start_time >= run_timeout)
  2182.         break;
  2183.         send_packets();
  2184.         bind_retry= bind_sockets();
  2185.         continue;
  2186.     }
  2187.     if ( rc == SOCKET_ERROR)  {
  2188.         perror("select");
  2189.         break;
  2190.     }
  2191.  
  2192.     gettimeofday( &packet_recv_time, NULL);
  2193.     fd= 0;
  2194.     for ( ; rc; rc--)  {
  2195.         struct sockaddr_in addr;
  2196.         int addrlen= sizeof(addr);
  2197.         server= get_next_ready_server();
  2198.         if ( server == NULL)
  2199.         break;
  2200.         if ( server->flags & FLAG_BROADCAST)
  2201.         pktlen= recvfrom( server->fd, pkt, sizeof(pkt_data), 0,
  2202.             (struct sockaddr*)&addr, &addrlen);
  2203.         else
  2204.             pktlen= recv( server->fd, pkt, sizeof(pkt_data), 0);
  2205.  
  2206.         if ( pktlen == SOCKET_ERROR)  {
  2207.         if ( connection_refused())  {
  2208.             server->server_name= DOWN;
  2209.             num_servers_down++;
  2210.             cleanup_qserver( server, 1);
  2211.             if ( ! connected)
  2212.             bind_retry= bind_sockets();
  2213.         }
  2214.         continue;
  2215.         }
  2216.         if ( server->flags & FLAG_BROADCAST)  {
  2217.         struct qserver *broadcast= server;
  2218.         /* create new server and init */
  2219.         server= add_qserver_byaddr( ntohl(addr.sin_addr.s_addr),
  2220.             ntohs(addr.sin_port), server->type, NULL);
  2221.         if ( server == NULL)  {
  2222.             if ( show_errors)  {
  2223.             fprintf(stderr,
  2224.                 "duplicate or invalid packet received from 0x%08x:%hu",
  2225.                 ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
  2226.             print_packet( NULL, pkt, pktlen);
  2227.             }
  2228.             continue;
  2229.         }
  2230.         server->packet_time1= broadcast->packet_time1;
  2231.         server->packet_time2= broadcast->packet_time2;
  2232.         server->ping_total= broadcast->ping_total;
  2233.         server->n_requests= broadcast->n_requests;
  2234.         server->n_packets= broadcast->n_packets;
  2235.         broadcast->n_servers++;
  2236.         }
  2237.  
  2238.         if ( show_recv_packets)
  2239.         print_packet( server, pkt, pktlen);
  2240.         server->type->packet_func( server, pkt, pktlen);
  2241.     }
  2242.  
  2243.     if ( run_timeout && time(0)-start_time >= run_timeout)
  2244.         break;
  2245.     if ( connected != last_connected)
  2246.         bind_retry= bind_sockets();
  2247.     }
  2248.  
  2249.     finish_output();
  2250.  
  2251.     return 0;
  2252. }
  2253.  
  2254. void
  2255. finish_output()
  2256. {
  2257.     int i;
  2258.     hcache_update_file();
  2259.  
  2260.     if ( progress)  {
  2261.     display_progress();
  2262.     fputs( "\n", stderr);
  2263.     }
  2264.  
  2265.     if ( server_sort)  {
  2266.     struct qserver **array, *server;
  2267.     if ( strchr( sort_keys, 'l') &&
  2268.         strpbrk( sort_keys, SUPPORTED_SERVER_SORT) == NULL)  {
  2269.         server= servers;
  2270.         for ( ; server; server= server->next)
  2271.         display_server( server);
  2272.     }
  2273.     else  {
  2274.     array= (struct qserver **) malloc( sizeof(struct qserver *) *
  2275.         num_servers_total);
  2276.     server= servers;
  2277.     for ( i= 0; server != NULL; i++)  {
  2278.         array[i]= server;
  2279.         server= server->next;
  2280.     }
  2281.     sort_servers( array, num_servers_total);
  2282.     if ( progress)
  2283.         fprintf( stderr, "\n");
  2284.     for ( i= 0; i < num_servers_total; i++)
  2285.         display_server( array[i]);
  2286.     free( array);
  2287.     }
  2288.     }
  2289.     else  {
  2290.     struct qserver *server;
  2291.     server= servers;
  2292.     for ( ; server; server= server->next)
  2293.         if ( server->server_name == HOSTNOTFOUND)
  2294.         display_server( server);
  2295.     }
  2296.  
  2297.     if ( xml_display)
  2298.     xml_footer();
  2299.     else if ( have_trailer_template())
  2300.     template_display_trailer();
  2301.  
  2302.     if ( OF != stdout)
  2303.     fclose( OF);
  2304. }
  2305.  
  2306.  
  2307. void
  2308. add_file( char *filename)
  2309. {
  2310.     FILE *file;
  2311.     char name[200], *comma, *query_arg;
  2312.     server_type* type;
  2313.  
  2314.     if ( strcmp( filename, "-") == 0)  {
  2315.     file= stdin;
  2316.     current_filename= NULL;
  2317.     }
  2318.     else  {
  2319.     file= fopen( filename, "r");
  2320.     current_filename= filename;
  2321.     }
  2322.     current_fileline= 1;
  2323.  
  2324.     if ( file == NULL)  {
  2325.     perror( filename);
  2326.     return;
  2327.     }
  2328.     for ( ; fscanf( file, "%s", name) == 1; current_fileline++)  {
  2329.     comma= strchr( name, ',');
  2330.     if ( comma)  {
  2331.         *comma++= '\0';
  2332.         query_arg= strdup( comma);
  2333.     }
  2334.     type= find_server_type_string( name);
  2335.     if ( type == NULL)
  2336.         add_qserver( name, default_server_type, NULL, NULL);
  2337.     else if ( fscanf( file, "%s", name) == 1)  {
  2338.         if ( type->flags & TF_QUERY_ARG && comma && *query_arg)
  2339.         add_qserver( name, type, NULL, query_arg);
  2340.         else
  2341.         add_qserver( name, type, NULL, NULL);
  2342.     }
  2343.     }
  2344.  
  2345.     if ( file != stdin)
  2346.     fclose(file);
  2347.  
  2348.     current_fileline= 0;
  2349. }
  2350.  
  2351. void
  2352. print_file_location()
  2353. {
  2354.     if ( current_fileline != 0)
  2355.     fprintf( stderr, "%s:%d: ", current_filename?current_filename:"<stdin>",
  2356.         current_fileline);
  2357. }
  2358.  
  2359. void
  2360. parse_query_params( struct qserver *server, char *params)
  2361. {
  2362.     char *comma, *arg= params;
  2363.     do  {
  2364.     comma= strchr(arg,',');
  2365.     if ( comma)
  2366.         *comma= '\0';
  2367.     if ( strchr( arg, '='))
  2368.         add_query_param( server, arg);
  2369.     arg= comma+1;
  2370.     } while ( comma);
  2371. }
  2372.  
  2373. int
  2374. add_qserver( char *arg, server_type* type, char *outfilename, char *query_arg)
  2375. {
  2376.     struct qserver *server;
  2377.     int flags= 0;
  2378.     char *colon= NULL, *arg_copy, *hostname= NULL;
  2379.     unsigned int ipaddr;
  2380.     unsigned short port;
  2381.  
  2382.     if ( run_timeout && time(0)-start_time >= run_timeout)  {
  2383.     finish_output();
  2384.     exit(0);
  2385.     }
  2386.  
  2387.     port= type->default_port;
  2388.  
  2389.     if ( outfilename && strcmp( outfilename, "-") != 0)  {
  2390.     FILE *outfile= fopen( outfilename, "r+");
  2391.     if ( outfile == NULL && (errno == EACCES || errno == EISDIR ||
  2392.         errno == ENOSPC || errno == ENOTDIR))  {
  2393.         perror( outfilename);
  2394.         return -1;
  2395.     }
  2396.     if ( outfile)
  2397.         fclose(outfile);
  2398.     }
  2399.  
  2400.     arg_copy= strdup(arg);
  2401.  
  2402.     colon= strchr( arg, ':');
  2403.     if ( colon != NULL)  {
  2404.     sscanf( colon+1, "%hd", &port);
  2405.     *colon= '\0';
  2406.     }
  2407.  
  2408.     if ( *arg == '+')  {
  2409.     flags|= FLAG_BROADCAST;
  2410.     arg++;
  2411.     }
  2412.  
  2413.     ipaddr= inet_addr(arg);
  2414.     if ( ipaddr == INADDR_NONE)  {
  2415.     if ( strcmp( arg, "255.255.255.255") != 0)
  2416.         ipaddr= htonl( hcache_lookup_hostname(arg));
  2417.     }
  2418.     else if ( hostname_lookup && !(flags&FLAG_BROADCAST))
  2419.     hostname= hcache_lookup_ipaddr( ntohl(ipaddr));
  2420.  
  2421.     if ( ipaddr == INADDR_NONE && strcmp( arg, "255.255.255.255") != 0)  {
  2422.     print_file_location();
  2423.     fprintf( stderr, "%s: %s\n", arg, strherror(h_errno));
  2424.     server= (struct qserver *) calloc( 1, sizeof( struct qserver));
  2425.     init_qserver( server);
  2426.     server->arg= arg_copy;
  2427.     server->server_name= HOSTNOTFOUND;
  2428.     server->error= strdup( strherror(h_errno));
  2429.     server->port= port;
  2430.     server->type= type;
  2431.     *last_server= server;
  2432.     last_server= & server->next;
  2433.     if ( one_server_type_id == ~MASTER_SERVER)
  2434.         one_server_type_id= type->id;
  2435.     else if ( one_server_type_id != type->id)
  2436.         one_server_type_id= 0;
  2437.         return -1;
  2438.     }
  2439.  
  2440.     if ( find_server_by_address( ipaddr, port) != NULL)
  2441.     return 0;
  2442.  
  2443.     server= (struct qserver *) calloc( 1, sizeof( struct qserver));
  2444.     server->arg= arg_copy;
  2445.     if ( hostname && colon)  {
  2446.     server->host_name= (char*)malloc( strlen(hostname) + strlen(colon+1)+2);
  2447.     sprintf( server->host_name, "%s:%s", hostname, colon+1);
  2448.     }
  2449.     else
  2450.     server->host_name= strdup((hostname)?hostname:arg);
  2451.  
  2452.     server->ipaddr= ipaddr;
  2453.     server->port= port;
  2454.     server->type= type;
  2455.     server->outfilename= outfilename;
  2456.     server->query_arg= query_arg;
  2457.     server->flags= flags;
  2458.     if ( query_arg)
  2459.     parse_query_params( server, query_arg);
  2460.     init_qserver( server);
  2461.  
  2462.     if ( server->type->master)
  2463.     waiting_for_masters++;
  2464.  
  2465.     if ( num_servers_total % 10 == 0)
  2466.     hcache_update_file();
  2467.  
  2468.     *last_server= server;
  2469.     last_server= & server->next;
  2470.  
  2471.     add_server_to_hash( server);
  2472.  
  2473.     if ( one_server_type_id == ~MASTER_SERVER)
  2474.     one_server_type_id= type->id;
  2475.     else if ( one_server_type_id != type->id)
  2476.     one_server_type_id= 0;
  2477.  
  2478.     return 0;
  2479. }
  2480.  
  2481. struct qserver *
  2482. add_qserver_byaddr( unsigned int ipaddr, unsigned short port,
  2483.     server_type* type, int *new_server)
  2484. {
  2485.     char arg[36];
  2486.     struct qserver *server;
  2487.     char *hostname= NULL;
  2488.  
  2489.     if ( run_timeout && time(0)-start_time >= run_timeout)  {
  2490.     finish_output();
  2491.     exit(0);
  2492.     }
  2493.  
  2494.     if ( new_server)
  2495.     *new_server= 0;
  2496.     ipaddr= htonl(ipaddr);
  2497.     if ( find_server_by_address( ipaddr, port) != NULL)
  2498.     return 0;
  2499.  
  2500.     if ( new_server)
  2501.     *new_server= 1;
  2502.  
  2503.     server= (struct qserver *) calloc( 1, sizeof( struct qserver));
  2504.     server->ipaddr= ipaddr;
  2505.     ipaddr= ntohl(ipaddr);
  2506.     sprintf( arg, "%d.%d.%d.%d:%hu", ipaddr>>24, (ipaddr>>16)&0xff,
  2507.     (ipaddr>>8)&0xff, ipaddr&0xff, port);
  2508.     server->arg= strdup(arg);
  2509.  
  2510.     if ( hostname_lookup)
  2511.     hostname= hcache_lookup_ipaddr( ipaddr);
  2512.     if ( hostname)  {
  2513.     server->host_name= (char*)malloc( strlen(hostname) + 6 + 2);
  2514.     sprintf( server->host_name, "%s:%hu", hostname, port);
  2515.     }
  2516.     else
  2517.     server->host_name= strdup( arg);
  2518.  
  2519.     server->port= port;
  2520.     server->type= type;
  2521.     init_qserver( server);
  2522.  
  2523.     if ( num_servers_total % 10 == 0)
  2524.     hcache_update_file();
  2525.  
  2526.     *last_server= server;
  2527.     last_server= & server->next;
  2528.  
  2529.     add_server_to_hash( server);
  2530.  
  2531.     return server;
  2532. }
  2533.  
  2534. void
  2535. add_servers_from_masters()
  2536. {
  2537.     struct qserver *server;
  2538.     unsigned int ipaddr, i;
  2539.     unsigned short port;
  2540.     int n_servers, new_server, port_adjust= 0;
  2541.     char *pkt;
  2542.     server_type* server_type;
  2543.     FILE *outfile;
  2544.  
  2545.     for ( server= servers; server != NULL; server= server->next)  {
  2546.     if ( !server->type->master || server->master_pkt == NULL)
  2547.         continue;
  2548.     pkt= server->master_pkt;
  2549.  
  2550.     if ( server->query_arg && server->type->id == GAMESPY_MASTER)  {
  2551.         server_type= find_server_type_string( server->query_arg);
  2552.         if ( server_type == NULL)
  2553.         server_type= find_server_type_id( server->type->master);
  2554.     }
  2555.     else
  2556.         server_type= find_server_type_id( server->type->master);
  2557.  
  2558.     if ( server->type->id == GAMESPY_MASTER && server_type)  {
  2559.         if ( server_type->id == UN_SERVER)
  2560.         port_adjust= -1;
  2561.         else if ( server_type->id == KINGPIN_SERVER)
  2562.         port_adjust= 10;
  2563.     }
  2564.  
  2565.     outfile= NULL;
  2566.     if ( server->outfilename)  {
  2567.         if ( strcmp( server->outfilename, "-") == 0)
  2568.         outfile= stdout;
  2569.         else
  2570.             outfile= fopen( server->outfilename, "w");
  2571.         if ( outfile == NULL)  {
  2572.         perror( server->outfilename);
  2573.         continue;
  2574.         }
  2575.     }
  2576.     n_servers= 0;
  2577.     for ( i= 0; i < server->master_pkt_len; i+= 6)  {
  2578.         memcpy( &ipaddr, &pkt[i], 4);
  2579.         memcpy( &port, &pkt[i+4], 2);
  2580.         ipaddr= ntohl( ipaddr);
  2581.         port= ntohs( port) + port_adjust;
  2582.         new_server= 1;
  2583.         if ( outfile)
  2584.         fprintf( outfile, "%s %d.%d.%d.%d:%hu\n",
  2585.             server_type ? server_type->type_string : "",
  2586.             (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
  2587.             (ipaddr>>8)&0xff, ipaddr&0xff, port);
  2588.         else if ( server_type == NULL)
  2589.         fprintf( OF, "%d.%d.%d.%d:%hu\n",
  2590.             (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
  2591.             (ipaddr>>8)&0xff, ipaddr&0xff, port);
  2592.         else
  2593.         add_qserver_byaddr( ipaddr, port, server_type, &new_server);
  2594.         n_servers+= new_server;
  2595.     }
  2596.     free( server->master_pkt);
  2597.     server->master_pkt= NULL;
  2598.     server->master_pkt_len= 0;
  2599.     server->n_servers= n_servers;
  2600.     if ( outfile)
  2601.         fclose( outfile);
  2602.     }
  2603.     if ( hostname_lookup)
  2604.     hcache_update_file();
  2605.     bind_sockets();
  2606. }
  2607.  
  2608. void
  2609. init_qserver( struct qserver *server)
  2610. {
  2611.     server->server_name= NULL;
  2612.     server->map_name= NULL;
  2613.     server->game= NULL;
  2614.     server->num_players= 0;
  2615.     server->fd= -1;
  2616.     if ( server->flags & FLAG_BROADCAST)  {
  2617.     server->retry1= 1;
  2618.     server->retry2= 1;
  2619.     }
  2620.     else  {
  2621.     server->retry1= n_retries;
  2622.     server->retry2= n_retries;
  2623.     }
  2624.     server->n_retries= 0;
  2625.     server->ping_total= 0;
  2626.     server->n_packets= 0;
  2627.     server->n_requests= 0;
  2628.  
  2629.     server->n_servers= 0;
  2630.     server->master_pkt_len= 0;
  2631.     server->master_pkt= NULL;
  2632.     server->error= NULL;
  2633.  
  2634.     server->saved_data.data= NULL;
  2635.     server->saved_data.datalen= 0;
  2636.     server->saved_data.pkt_index= -1;
  2637.     server->saved_data.pkt_max= 0;
  2638.     server->saved_data.next= NULL;
  2639.  
  2640.     server->next_rule= (get_server_rules) ? "" : NO_SERVER_RULES;
  2641.     server->next_player_info= (get_player_info) ? 0 : NO_PLAYER_INFO;
  2642.  
  2643.     server->n_player_info= 0;
  2644.     server->players= NULL;
  2645.     server->n_rules= 0;
  2646.     server->rules= NULL;
  2647.     server->last_rule= &server->rules;
  2648.     server->missing_rules= 0;
  2649.  
  2650.     num_servers_total++;
  2651. }
  2652.  
  2653. struct qserver *
  2654. find_server_by_address( unsigned int ipaddr, unsigned short port)
  2655. {
  2656.     struct qserver **server;
  2657.     unsigned int hash, i;
  2658.     hash= (ipaddr + port) % ADDRESS_HASH_LENGTH;
  2659.  
  2660.     if ( ipaddr == 0)  {
  2661.     for ( hash= 0; hash < ADDRESS_HASH_LENGTH; hash++)
  2662.         printf( "%3d %d\n", hash, server_hash_len[hash]);
  2663.     return NULL;
  2664.     }
  2665.  
  2666.     server= server_hash[hash];
  2667.     for ( i= server_hash_len[hash]; i; i--, server++)
  2668.     if ( (*server)->ipaddr == ipaddr && (*server)->port == port)
  2669.         return *server;
  2670.     return NULL;
  2671. }
  2672.  
  2673. void
  2674. add_server_to_hash( struct qserver *server)
  2675. {
  2676.     unsigned int hash;
  2677.     hash= (server->ipaddr + server->port) % ADDRESS_HASH_LENGTH;
  2678.  
  2679.     if ( server_hash_len[hash] % 16 == 0)  {
  2680.     server_hash[hash]= (struct qserver**) realloc( server_hash[hash],
  2681.         sizeof( struct qserver **) * (server_hash_len[hash]+16));
  2682.     memset( &server_hash[hash][server_hash_len[hash]], 0,
  2683.         sizeof( struct qserver **) * 16);
  2684.     }
  2685.     server_hash[hash][server_hash_len[hash]]= server;
  2686.     server_hash_len[hash]++;
  2687. }
  2688.  
  2689. /* Functions for binding sockets to Quake servers
  2690.  */
  2691. int
  2692. bind_qserver( struct qserver *server)
  2693. {
  2694.     struct sockaddr_in addr;
  2695.     static int one= 1;
  2696.  
  2697.     if ( server->type->flags & TF_TCP_CONNECT)
  2698.     server->fd= socket( AF_INET, SOCK_STREAM, 0);
  2699.     else
  2700.     server->fd= socket( AF_INET, SOCK_DGRAM, 0);
  2701.  
  2702.     if ( server->fd == INVALID_SOCKET) {
  2703.     if ( sockerr() == EMFILE)  {
  2704.         server->fd= -1;
  2705.         return -2;
  2706.     }
  2707.         perror( "socket" );
  2708.     server->server_name= SYSERROR;
  2709.         return -1;
  2710.     }
  2711.  
  2712.     addr.sin_family = AF_INET;
  2713.     addr.sin_addr.s_addr = htonl( source_ip);
  2714.     if ( server->type->id == Q2_MASTER)
  2715.     addr.sin_port= htons(26500);
  2716.     else if ( source_port == 0)
  2717.     addr.sin_port= 0;
  2718.     else  {
  2719.     addr.sin_port= htons( source_port);
  2720.     source_port++;
  2721.     if ( source_port > source_port_high)
  2722.         source_port= source_port_low;
  2723.     }
  2724.     memset( &(addr.sin_zero), 0, sizeof(addr.sin_zero) );
  2725.  
  2726.     if ( bind( server->fd, (struct sockaddr *)&addr,
  2727.         sizeof(struct sockaddr)) == SOCKET_ERROR) {
  2728.     if ( sockerr() != EADDRINUSE)  {
  2729.         perror( "bind" );
  2730.         server->server_name= SYSERROR;
  2731.     }
  2732.     close(server->fd);
  2733.     server->fd= -1;
  2734.         return -1;
  2735.     }
  2736.  
  2737.     if ( server->flags & FLAG_BROADCAST)
  2738.     setsockopt( server->fd, SOL_SOCKET, SO_BROADCAST, (char*)&one,
  2739.         sizeof(one));
  2740.  
  2741.     if ( server->type->id != Q2_MASTER &&
  2742.         !(server->flags & FLAG_BROADCAST))  {
  2743.     addr.sin_family= AF_INET;
  2744.     addr.sin_port= htons(server->port + server->type->port_offset);
  2745.     addr.sin_addr.s_addr= server->ipaddr;
  2746.     memset( &(addr.sin_zero), 0, sizeof(addr.sin_zero) );
  2747.  
  2748.     if ( connect( server->fd, (struct sockaddr *)&addr, sizeof(addr)) ==
  2749.         SOCKET_ERROR)  {
  2750.         if ( server->type->id == UN_MASTER)  {
  2751.         if ( connection_refused())  {
  2752.         /*  server->fd= -2; */
  2753.         /* set up for connect retry */
  2754.         }
  2755.         }
  2756.         perror( "connect");
  2757.         server->server_name= SYSERROR;
  2758.         close(server->fd);
  2759.         server->fd= -1;
  2760.         return -1;
  2761.     }
  2762.     }
  2763.  
  2764.     if ( server->type->flags & TF_TCP_CONNECT)  {
  2765.     int one= 1;
  2766.     set_non_blocking( server->fd);
  2767.     setsockopt( server->fd, IPPROTO_TCP, TCP_NODELAY,
  2768.         (char*) &one, sizeof(one));
  2769.     }
  2770.  
  2771. #ifdef _ISUNIX
  2772.     if ( server->fd >= max_connmap)  {
  2773.     int old_max= max_connmap;
  2774.     max_connmap= server->fd + 32;
  2775.     connmap= (struct qserver **) realloc( connmap, max_connmap *
  2776.         sizeof( struct qserver *));
  2777.     memset( &connmap[old_max], 0, (max_connmap - old_max) *
  2778.         sizeof( struct qserver *));
  2779.     }
  2780.     connmap[server->fd]= server;
  2781. #endif
  2782. #ifdef _WIN32
  2783.     { int i;
  2784.     for ( i= 0; i < max_connmap; i++)  {
  2785.     if ( connmap[i] == NULL)  {
  2786.         connmap[i]= server;
  2787.         break;
  2788.     }
  2789.     }
  2790.     if ( i >= max_connmap) printf( "could not put server in connmap\n");
  2791.     }
  2792. #endif
  2793.  
  2794.     return 0;
  2795. }
  2796.  
  2797. int
  2798. bind_sockets()
  2799. {
  2800.     struct qserver *server;
  2801.     int rc, retry_count= 0;;
  2802.  
  2803.     if ( !waiting_for_masters)  {
  2804.     if ( last_server_bind == NULL)
  2805.         last_server_bind= servers;
  2806.     server= last_server_bind;
  2807.     }
  2808.     else
  2809.     server= servers;
  2810.  
  2811.     for ( ; server != NULL && connected < max_simultaneous;
  2812.         server= server->next)  {
  2813.     if ( server->server_name == NULL && server->fd == -1)  {
  2814.         if ( waiting_for_masters && !server->type->master)
  2815.         continue;
  2816.         if ( (rc= bind_qserver( server)) == 0)  {
  2817.         server->type->status_query_func( server);
  2818.         connected++;
  2819.         if ( !waiting_for_masters)
  2820.             last_server_bind= server;
  2821.         }
  2822.         else if ( rc == -2 && ++retry_count > 2)
  2823.         return -2;
  2824.     }
  2825.     }
  2826.     if ( ! connected && retry_count)
  2827.     return -2;
  2828.     return 0;
  2829. }
  2830.  
  2831.  
  2832. /* Functions for sending packets
  2833.  */
  2834. void
  2835. send_packets()
  2836. {
  2837.     struct qserver *server= servers;
  2838.     struct timeval now;
  2839.     int interval, n_sent=0, prev_n_sent;
  2840.  
  2841.     gettimeofday( &now, NULL);
  2842.  
  2843.     for ( ; server != NULL; server= server->next)  {
  2844.     if ( server->fd == -1)
  2845.         continue;
  2846.     if ( server->type->id & MASTER_SERVER)
  2847.         interval= master_retry_interval;
  2848.     else
  2849.         interval= retry_interval;
  2850.     prev_n_sent= n_sent;
  2851.     if ( server->server_name == NULL ||
  2852.         !(server->type->flags & TF_SINGLE_QUERY) )  { 
  2853.         if ( server->retry1 != n_retries &&
  2854.             time_delta( &now, &server->packet_time1) <
  2855.             (interval*(n_retries-server->retry1+1)))
  2856.         continue;
  2857.         if ( ! server->retry1)  {
  2858.         cleanup_qserver( server, 1);
  2859.         continue;
  2860.         }
  2861.         server->type->status_query_func( server);
  2862.         n_sent++;
  2863.         continue;
  2864.     }
  2865.     if ( server->next_rule != NO_SERVER_RULES)  {
  2866.         if ( server->retry1 != n_retries &&
  2867.             time_delta( &now, &server->packet_time1) <
  2868.             (interval*(n_retries-server->retry1+1)))
  2869.         continue;
  2870.         if ( ! server->retry1)  {
  2871.         server->next_rule= NULL;
  2872.         server->missing_rules= 1;
  2873.         cleanup_qserver( server, 0);
  2874.         continue;
  2875.         }
  2876.         send_rule_request_packet( server);
  2877.         n_sent++;
  2878.     }
  2879.     if ( server->next_player_info < server->num_players &&
  2880.         server->type->player_packet)  {
  2881.         if ( server->retry2 != n_retries &&
  2882.             time_delta( &now, &server->packet_time2) <
  2883.             (interval*(n_retries-server->retry2+1)))
  2884.         continue;
  2885.         if ( ! server->retry2)  {
  2886.         server->next_player_info++;
  2887.         if ( server->next_player_info >= server->num_players)  {
  2888.             cleanup_qserver( server, 0);
  2889.             continue;
  2890.         }
  2891.         server->retry2= n_retries;
  2892.         }
  2893.         send_player_request_packet( server);
  2894.         n_sent++;
  2895.     }
  2896.     if ( prev_n_sent == n_sent)  {
  2897.         if ( ! server->retry1 && time_delta( &now, &server->packet_time1) > 
  2898.             (interval*(n_retries+1)))
  2899.         cleanup_qserver( server, 1);
  2900.     }
  2901.     }
  2902. }
  2903.  
  2904. int
  2905. send_broadcast( struct qserver *server, char *pkt, int pktlen)
  2906. {
  2907.     struct sockaddr_in addr;
  2908.     addr.sin_family= AF_INET;
  2909.     addr.sin_port= htons(server->port + server->type->port_offset);
  2910.     addr.sin_addr.s_addr= server->ipaddr;
  2911.     memset( &(addr.sin_zero), 0, sizeof(addr.sin_zero));
  2912.     return sendto( server->fd, (const char*) pkt, pktlen, 0,
  2913.         (struct sockaddr *) &addr, sizeof(addr));
  2914. }
  2915.  
  2916. /* server starts sending data immediately, so we need not do anything */
  2917. void
  2918. send_bfris_request_packet( struct qserver *server)
  2919. {
  2920.  
  2921.   if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST)  {
  2922.     gettimeofday( &server->packet_time1, NULL);
  2923.     server->n_requests++;
  2924.   }
  2925.   else
  2926.     server->n_retries++;
  2927.  
  2928.   server->retry1--;
  2929.   server->n_packets++;
  2930. }
  2931.  
  2932.  
  2933. /* First packet for a normal Quake server
  2934.  */
  2935. void
  2936. send_qserver_request_packet( struct qserver *server)
  2937. {
  2938.     int rc;
  2939.     if ( server->flags & FLAG_BROADCAST)
  2940.     rc= send_broadcast( server, server->type->status_packet,
  2941.         server->type->status_len);
  2942.     else
  2943.     rc= send( server->fd, server->type->status_packet,
  2944.         server->type->status_len, 0);
  2945.  
  2946.     if ( rc == SOCKET_ERROR)  {
  2947.     unsigned int ipaddr= ntohl(server->ipaddr);
  2948.     fprintf( stderr,
  2949.         "Error on %d.%d.%d.%d, skipping ...\n",
  2950.         (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
  2951.         (ipaddr>>8)&0xff, ipaddr&0xff);
  2952.     perror( "send");
  2953.     cleanup_qserver( server, 1);
  2954.     return;
  2955.     }
  2956.     if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST)  {
  2957.     gettimeofday( &server->packet_time1, NULL);
  2958.     server->n_requests++;
  2959.     }
  2960.     else
  2961.     server->n_retries++;
  2962.     server->retry1--;
  2963.     server->n_packets++;
  2964. }
  2965.  
  2966. /* First packet for a QuakeWorld server
  2967.  */
  2968. void
  2969. send_qwserver_request_packet( struct qserver *server)
  2970. {
  2971.     int rc;
  2972.  
  2973.     if ( server->flags & FLAG_BROADCAST)
  2974.     rc= send_broadcast( server, server->type->status_packet,
  2975.         server->type->status_len);
  2976.     else if ( server->server_name == NULL)
  2977.     rc= send( server->fd, server->type->status_packet,
  2978.         server->type->status_len, 0);
  2979.     else if ( server->server_name != NULL && server->type->rule_packet)
  2980.     rc= send( server->fd, server->type->rule_packet,
  2981.         server->type->rule_len, 0);
  2982.     else
  2983.     rc= SOCKET_ERROR;
  2984.  
  2985.     if ( rc == SOCKET_ERROR)  {
  2986.     unsigned int ipaddr= ntohl(server->ipaddr);
  2987.     fprintf( stderr,
  2988.         "Error on %d.%d.%d.%d, skipping ...\n",
  2989.         (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
  2990.         (ipaddr>>8)&0xff, ipaddr&0xff);
  2991.     perror( "send");
  2992.     cleanup_qserver( server, 1);
  2993.     return;
  2994.     }
  2995.     if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST)  {
  2996.     gettimeofday( &server->packet_time1, NULL);
  2997.     server->n_requests++;
  2998.     }
  2999.     else if ( server->server_name == NULL)
  3000.     server->n_retries++;
  3001.     server->retry1--;
  3002.     if ( server->server_name == NULL)
  3003.     server->n_packets++;
  3004. }
  3005.  
  3006. /* First packet for an Unreal server
  3007.  */
  3008. void
  3009. send_unreal_request_packet( struct qserver *server)
  3010. {
  3011.     int rc;
  3012.  
  3013.     if ( server->flags & FLAG_BROADCAST)
  3014.     rc= send_broadcast( server, server->type->status_packet,
  3015.         server->type->status_len);
  3016.     else   
  3017.     rc= send( server->fd, server->type->status_packet,
  3018.         server->type->status_len, 0);
  3019.  
  3020.     if ( rc == SOCKET_ERROR)
  3021.     perror( "send");
  3022.     if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST)  {
  3023.     gettimeofday( &server->packet_time1, NULL);
  3024.     server->n_requests++;
  3025.     }
  3026.     else
  3027.     server->n_retries++;
  3028.     server->retry1--;
  3029.     server->n_packets++;
  3030. }
  3031.  
  3032. /* First packet for an Unreal master
  3033.  */
  3034. void
  3035. send_unrealmaster_request_packet( struct qserver *server)
  3036. {
  3037.     int rc;
  3038.  
  3039.     rc= send( server->fd, server->type->status_packet,
  3040.     server->type->status_len, 0);
  3041.  
  3042.     if ( rc == SOCKET_ERROR)
  3043.     perror( "send");
  3044.     if ( server->retry1 == n_retries)  {
  3045.     gettimeofday( &server->packet_time1, NULL);
  3046.     server->n_requests++;
  3047.     }
  3048.     else
  3049.     server->n_retries++;
  3050.     server->retry1--;
  3051.     server->n_packets++;
  3052. }
  3053.  
  3054. char *
  3055. build_hlmaster_packet( struct qserver *server, int *len)
  3056. {
  3057.     static char packet[1600];
  3058.     char *pkt, *r, *sep= "";
  3059.     char *gamedir, *map, *flags;
  3060.     int flen;
  3061.  
  3062.     pkt= &packet[0];
  3063.     memcpy( pkt, server->type->master_packet, server->type->master_len);
  3064.  
  3065.     pkt+= server->type->master_len;
  3066.  
  3067.     gamedir= get_param_value( server, "game", NULL);
  3068.     if ( gamedir)
  3069.     pkt+= sprintf( pkt, "\\gamedir\\%s", gamedir);
  3070.     map= get_param_value( server, "map", NULL);
  3071.     if ( map)
  3072.     pkt+= sprintf( pkt, "\\map\\%s", map);
  3073.  
  3074.     flags= get_param_value( server, "status", NULL);
  3075.     r= flags;
  3076.     while ( flags && sep)  {
  3077.     sep= strchr( r, ':');
  3078.     if ( sep)
  3079.         flen= sep-r;
  3080.     else
  3081.         flen= strlen( r);
  3082.     if ( strncmp( r, "notempty", flen) == 0)
  3083.         pkt+= sprintf( pkt, "\\empty\\1");
  3084.     else if ( strncmp( r, "notfull", flen) == 0)
  3085.         pkt+= sprintf( pkt, "\\full\\1");
  3086.     else if ( strncmp( r, "dedicated", flen) == 0)
  3087.         pkt+= sprintf( pkt, "\\dedicated\\1");
  3088.     else if ( strncmp( r, "linux", flen) == 0)
  3089.         pkt+= sprintf( pkt, "\\linux\\1");
  3090.     r= sep+1;
  3091.     }
  3092.  
  3093.     *len= pkt - packet;
  3094.  
  3095.     return packet;
  3096. }
  3097.  
  3098. /* First packet for a QuakeWorld master server
  3099.  */
  3100. void
  3101. send_qwmaster_request_packet( struct qserver *server)
  3102. {
  3103.     int rc= 0, query_len= 0;
  3104.     char query_buf[4096];
  3105.  
  3106.     if ( server->type->master_len == 0)  {
  3107.     char *master_protocol= server->query_arg;
  3108.     if ( master_protocol == NULL)
  3109.         master_protocol= server->type->master_protocol;
  3110.     query_len= sprintf( query_buf, server->type->master_packet,
  3111.         master_protocol?master_protocol:"",
  3112.         server->type->master_query?server->type->master_query:"");
  3113.     }
  3114.  
  3115.     if ( server->type->id == Q2_MASTER)  {
  3116.     struct sockaddr_in addr;
  3117.     addr.sin_family= AF_INET;
  3118.     addr.sin_port= htons(server->port + server->type->port_offset);
  3119.     addr.sin_addr.s_addr= server->ipaddr;
  3120.     memset( &(addr.sin_zero), 0, sizeof(addr.sin_zero));
  3121.     rc= sendto( server->fd, server->type->master_packet,
  3122.         server->type->master_len, 0,
  3123.         (struct sockaddr *) &addr, sizeof(addr));
  3124.     }
  3125.     else  {
  3126.     char *packet;
  3127.     int packet_len;
  3128.     if ( query_len)  {
  3129.         packet= query_buf;
  3130.         packet_len= query_len;
  3131.     }
  3132.     else  {
  3133.         packet= server->type->master_packet;
  3134.         packet_len= server->type->master_len;
  3135.     }
  3136.     if ( server->type->id == HL_MASTER)  {
  3137.         memcpy( server->type->master_packet+1, server->master_query_tag, 3);
  3138.         if ( server->query_arg)
  3139.         packet= build_hlmaster_packet( server, &packet_len);
  3140.     }
  3141.     rc= send( server->fd, packet, packet_len, 0);
  3142.     }
  3143.  
  3144.     if ( rc == SOCKET_ERROR)
  3145.     perror( "send");
  3146.     if ( server->retry1 == n_retries)  {
  3147.     gettimeofday( &server->packet_time1, NULL);
  3148.     server->n_requests++;
  3149.     }
  3150.     else
  3151.     server->n_retries++;
  3152.     server->retry1--;
  3153.     server->n_packets++;
  3154. }
  3155.  
  3156. void
  3157. send_tribes_request_packet( struct qserver *server)
  3158. {
  3159.     int rc;
  3160.  
  3161.     if ( get_player_info || get_server_rules)  {
  3162.     if ( server->flags & FLAG_BROADCAST && server->server_name == NULL)
  3163.         rc= send_broadcast( server, server->type->player_packet,
  3164.         server->type->player_len);
  3165.     else
  3166.         rc= send( server->fd, server->type->player_packet,
  3167.         server->type->player_len, 0);
  3168.     }
  3169.     else  {
  3170.     if ( server->flags & FLAG_BROADCAST && server->server_name == NULL)
  3171.         rc= send_broadcast( server, server->type->status_packet,
  3172.         server->type->status_len);
  3173.     else
  3174.         rc= send( server->fd, server->type->status_packet,
  3175.         server->type->status_len, 0);
  3176.     }
  3177.  
  3178.     if ( rc == SOCKET_ERROR)
  3179.     perror( "send");
  3180.     if ( server->retry1 == n_retries)  {
  3181.     gettimeofday( &server->packet_time1, NULL);
  3182.     server->n_requests++;
  3183.     }
  3184.     else
  3185.     server->n_retries++;
  3186.     server->retry1--;
  3187.     server->n_packets++;
  3188. }
  3189.  
  3190. void
  3191. send_tribes2_request_packet( struct qserver *server)
  3192. {
  3193.     int rc;
  3194.  
  3195.     if ( server->flags & FLAG_BROADCAST && server->server_name == NULL)
  3196.     rc= send_broadcast( server, server->type->status_packet,
  3197.         server->type->status_len);
  3198.     else if ( server->server_name == NULL)
  3199.     rc= send( server->fd, server->type->status_packet,
  3200.         server->type->status_len, 0);
  3201.     else
  3202.     rc= send( server->fd, server->type->player_packet,
  3203.         server->type->status_len, 0);
  3204.  
  3205.     if ( rc == SOCKET_ERROR)
  3206.     perror( "send");
  3207.     if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST)  {
  3208.     gettimeofday( &server->packet_time1, NULL);
  3209.     server->n_requests++;
  3210.     }
  3211.     else
  3212.     server->n_retries++;
  3213.     server->retry1--;
  3214.     server->n_packets++;
  3215. }
  3216.  
  3217. void
  3218. send_tribes2master_request_packet( struct qserver *server)
  3219. {
  3220.     int rc;
  3221.     unsigned char packet[1600], *pkt;
  3222.     unsigned int len, min_players, max_players, region_mask=0;
  3223.     unsigned int build_version, max_bots, min_cpu, status;
  3224.     char *game, *mission, *buddies;
  3225.     static char *region_list[]= { "naeast", "nawest", "sa", "aus", "asia", "eur", NULL };
  3226.     static char *status_list[]= { "dedicated", "nopassword", "linux" };
  3227.  
  3228.     if ( strcmp( get_param_value( server, "query", ""), "types") == 0)  {
  3229.     rc= send( server->fd, tribes2_game_types_request,
  3230.         sizeof(tribes2_game_types_request), 0);
  3231.     goto send_done;
  3232.     }
  3233.  
  3234.     memcpy( packet, server->type->master_packet, server->type->master_len);
  3235.  
  3236.     pkt= packet + 7;
  3237.  
  3238.     game= get_param_value( server, "game", "any");
  3239.     len= strlen(game);
  3240.     if ( len > 255) len= 255;
  3241.     *pkt++= len;
  3242.     memcpy( pkt, game, len);
  3243.     pkt+= len;
  3244.  
  3245.     mission= get_param_value( server, "mission", "any");
  3246.     len= strlen(mission);
  3247.     if ( len > 255) len= 255;
  3248.     *pkt++= len;
  3249.     memcpy( pkt, mission, len);
  3250.     pkt+= len;
  3251.  
  3252.     min_players= get_param_ui_value( server, "minplayers", 0);
  3253.     max_players= get_param_ui_value( server, "maxplayers", 255);
  3254.     *pkt++= min_players;
  3255.     *pkt++= max_players;
  3256.  
  3257.     region_mask= get_param_ui_value( server, "regions", 0xffffffff);
  3258.     if ( region_mask == 0)  {
  3259.     char *regions= get_param_value( server, "regions", "");
  3260.     char *r= regions;
  3261.     char **list, *sep;
  3262.     do  {
  3263.         sep= strchr( r, ':');
  3264.         if ( sep)
  3265.         len= sep-r;
  3266.         else
  3267.         len= strlen( r);
  3268.         for ( list= region_list; *list; list++)
  3269.         if ( strncasecmp( r, *list, len) == 0)
  3270.             break;
  3271.         if ( *list)
  3272.         region_mask|= 1<<(list-region_list);
  3273.         r= sep+1;
  3274.     } while ( sep);
  3275.     }
  3276.     if ( little_endian)
  3277.     memcpy( pkt, ®ion_mask, 4);
  3278.     else  {
  3279.         pkt[0]= region_mask&0xff;
  3280.         pkt[1]= (region_mask>>8)&0xff;
  3281.         pkt[2]= (region_mask>>16)&0xff;
  3282.         pkt[3]= (region_mask>>24)&0xff;
  3283.     }
  3284.     pkt+= 4;
  3285.  
  3286.     build_version= get_param_ui_value( server, "build", 0);
  3287. /*
  3288.     if ( build_version && build_version < 22337)  {
  3289.     packet[1]= 0;
  3290.     build_version= 0;
  3291.     }
  3292. */
  3293.     if ( little_endian)
  3294.     memcpy( pkt, &build_version, 4);
  3295.     else  {
  3296.         pkt[0]= build_version&0xff;
  3297.         pkt[1]= (build_version>>8)&0xff;
  3298.         pkt[2]= (build_version>>16)&0xff;
  3299.         pkt[3]= (build_version>>24)&0xff;
  3300.     }
  3301.     pkt+= 4;
  3302.  
  3303.     status= get_param_ui_value( server, "status", -1);
  3304.     if ( status == 0)  {
  3305.     char *flags= get_param_value( server, "status", "");
  3306.     char *r= flags;
  3307.     char **list, *sep;
  3308.     do  {
  3309.         sep= strchr( r, ':');
  3310.         if ( sep)
  3311.         len= sep-r;
  3312.         else
  3313.         len= strlen( r);
  3314.         for ( list= status_list; *list; list++)
  3315.         if ( strncasecmp( r, *list, len) == 0)
  3316.             break;
  3317.         if ( *list)
  3318.         status|= 1<<(list-status_list);
  3319.         r= sep+1;
  3320.     } while ( sep);
  3321.     }
  3322.     else if ( status == -1)
  3323.     status= 0;
  3324.     *pkt++= status;
  3325.  
  3326.     max_bots= get_param_ui_value( server, "maxbots", 255);
  3327.     *pkt++= max_bots;
  3328.  
  3329.     min_cpu= get_param_ui_value( server, "mincpu", 0);
  3330.     if ( little_endian)
  3331.     memcpy( pkt, &min_cpu, 2);
  3332.     else  {
  3333.         pkt[0]= min_cpu&0xff;
  3334.         pkt[1]= (min_cpu>>8)&0xff;
  3335.     }
  3336.     pkt+= 2;
  3337.  
  3338.     buddies= get_param_value( server, "buddies", NULL);
  3339.     if ( buddies)  {
  3340.     char *b= buddies, *sep;
  3341.     unsigned int buddy, n_buddies= 0;
  3342.     unsigned char *n_loc= pkt++;
  3343.     do  {
  3344.         sep= strchr( b, ':');
  3345.         if ( sscanf( b, "%u", &buddy))  {
  3346.         n_buddies++;
  3347.         if ( little_endian)
  3348.             memcpy( pkt, &buddy, 4);
  3349.         else  {
  3350.             pkt[0]= buddy&0xff;
  3351.             pkt[1]= (buddy>>8)&0xff;
  3352.             pkt[2]= (buddy>>16)&0xff;
  3353.             pkt[3]= (buddy>>24)&0xff;
  3354.         }
  3355.         pkt+= 4;
  3356.         }
  3357.         b= sep+1;
  3358.     } while ( sep && n_buddies < 255);
  3359.     *n_loc= n_buddies;
  3360.     }
  3361.     else
  3362.     *pkt++= 0;
  3363.  
  3364.     rc= send( server->fd, (char*)packet, pkt-packet, 0);
  3365.  
  3366. send_done:
  3367.     if ( rc == SOCKET_ERROR)
  3368.     perror( "send");
  3369.     if ( server->retry1 == n_retries)  {
  3370.     gettimeofday( &server->packet_time1, NULL);
  3371.     server->n_requests++;
  3372.     }
  3373.     else
  3374.     server->n_retries++;
  3375.     server->retry1--;
  3376.     server->n_packets++;
  3377. }
  3378.  
  3379. static struct _gamespy_query_map  {
  3380.     char *qstat_type;
  3381.     char *gamespy_type;
  3382. } gamespy_query_map[] = {
  3383.     "qws", "quakeworld",
  3384.     "q2s", "quake2",
  3385.     "q3s", "quake3",
  3386.     "tbs", "tribes",
  3387.     "uns", "ut",
  3388.     "sgs", "shogo",
  3389.     "hls", "halflife",
  3390.     "kps", "kingpin",
  3391.     "hrs", "heretic2",
  3392.     "sfs", "sofretail",
  3393.     NULL, NULL
  3394. };
  3395.  
  3396. void
  3397. send_gamespy_master_request( struct qserver *server)
  3398. {
  3399.     int rc, i;
  3400.     char request[1024];
  3401.  
  3402.     if ( server->n_packets)
  3403.     return;
  3404.  
  3405.     rc= send( server->fd, server->type->master_packet,
  3406.     server->type->master_len, 0);
  3407.     if ( rc != server->type->master_len)
  3408.     perror( "send");
  3409.  
  3410.     strcpy( request, server->type->status_packet);
  3411.  
  3412.     for ( i= 0; gamespy_query_map[i].qstat_type; i++)
  3413.     if ( strcasecmp( server->query_arg, gamespy_query_map[i].qstat_type) == 0)
  3414.         break;
  3415.     if ( gamespy_query_map[i].gamespy_type == NULL)
  3416.     strcat( request, server->query_arg);
  3417.     else
  3418.     strcat( request, gamespy_query_map[i].gamespy_type);
  3419.  
  3420.     rc= send( server->fd, request, strlen( request), 0);
  3421.     if ( rc != strlen( request))
  3422.     perror( "send");
  3423.  
  3424.     if ( server->retry1 == n_retries)  {
  3425.     gettimeofday( &server->packet_time1, NULL);
  3426.     server->n_requests++;
  3427.     }
  3428.     server->n_packets++;
  3429. }
  3430.  
  3431. void
  3432. send_rule_request_packet( struct qserver *server)
  3433. {
  3434.     int rc, len;
  3435.  
  3436.     /* Server created via broadcast, so bind it */
  3437.     if ( server->fd == -1)  {
  3438.     if ( bind_qserver( server) < 0)
  3439.         goto setup_retry;
  3440.     }
  3441.  
  3442.     if ( server->type->id == Q_SERVER)  {
  3443.     strcpy( (char*)q_rule.data, server->next_rule);
  3444.     len= Q_HEADER_LEN + strlen((char*)q_rule.data) + 1;
  3445.     q_rule.length= htons( (short)len);
  3446.     }
  3447.     else
  3448.     len= server->type->rule_len;
  3449.  
  3450.     rc= send( server->fd, (const char *) server->type->rule_packet,
  3451.     len, 0);
  3452.     if ( rc == SOCKET_ERROR)
  3453.     perror( "send");
  3454.  
  3455. setup_retry:
  3456.     if ( server->retry1 == n_retries)  {
  3457.     gettimeofday( &server->packet_time1, NULL);
  3458.     server->n_requests++;
  3459.     }
  3460.     else if ( server->server_name == NULL)
  3461.     server->n_retries++;
  3462.     server->retry1--;
  3463.     if ( server->server_name == NULL)
  3464.     server->n_packets++;
  3465. }
  3466.  
  3467. void
  3468. send_player_request_packet( struct qserver *server)
  3469. {
  3470.     int rc;
  3471.  
  3472.     /* Server created via broadcast, so bind it */
  3473.     if ( server->fd == -1)  {
  3474.     if ( bind_qserver( server) < 0)
  3475.         goto setup_retry;
  3476.     }
  3477.  
  3478.     if ( server->type->id == Q_SERVER)
  3479.     q_player.data[0]= server->next_player_info;
  3480.     rc= send( server->fd, (const char *) server->type->player_packet,
  3481.     server->type->player_len, 0);
  3482.     if ( rc == SOCKET_ERROR)
  3483.     perror( "send");
  3484.  
  3485. setup_retry:
  3486.     if ( server->retry2 == n_retries)  {
  3487.     gettimeofday( &server->packet_time2, NULL);
  3488.     server->n_requests++;
  3489.     }
  3490.     else
  3491.     server->n_retries++;
  3492.     server->retry2--;
  3493.     server->n_packets++;
  3494. }
  3495.  
  3496. /* Functions for figuring timeouts and when to give up
  3497.  */
  3498. void
  3499. cleanup_qserver( struct qserver *server, int force)
  3500. {
  3501.     int close_it= force, i;
  3502.     if ( server->server_name == NULL)  {
  3503.     close_it= 1;
  3504.     if ( server->type->id & MASTER_SERVER && server->master_pkt != NULL)
  3505.         server->server_name= MASTER;
  3506.     else  {
  3507.         server->server_name= TIMEOUT;
  3508.         num_servers_timed_out++;
  3509.     }
  3510.     }
  3511.     else if ( server->type->flags & TF_SINGLE_QUERY)
  3512.     close_it= 1;
  3513.     else if ( server->next_rule == NO_SERVER_RULES &&
  3514.         server->next_player_info >= server->num_players)
  3515.     close_it= 1;
  3516.  
  3517.     if ( close_it)  {
  3518.  
  3519.     if ( server->saved_data.data) {
  3520.         SavedData *sdata= server->saved_data.next;
  3521.         free(server->saved_data.data);
  3522.         server->saved_data.data= NULL;
  3523.         while ( sdata != NULL)  {
  3524.         SavedData *next;
  3525.         free(sdata->data);
  3526.         next= sdata->next;
  3527.         free(sdata);
  3528.         sdata= next;
  3529.         }
  3530.         server->saved_data.next= NULL;
  3531.     }
  3532.  
  3533.     if ( server->fd != -1)  {
  3534.         close( server->fd);
  3535. #ifdef _ISUNIX
  3536.         connmap[server->fd]= NULL;
  3537. #endif
  3538. #ifdef _WIN32
  3539.         for ( i= 0; i < max_connmap; i++)  {
  3540.         if ( connmap[i] == server)  {
  3541.             connmap[i]= NULL;
  3542.             break;
  3543.         }
  3544.         }
  3545. #endif
  3546.         server->fd= -1;
  3547.         connected--;
  3548.     }
  3549.  
  3550.     if ( server->server_name != TIMEOUT)  {
  3551.         num_servers_returned++;
  3552.         if ( server->server_name != DOWN)
  3553.         num_players_total+= server->num_players;
  3554.     }
  3555.     if ( server->server_name == TIMEOUT || server->server_name == DOWN)
  3556.         server->ping_total= 999999;
  3557.     if ( server->type->master)  {
  3558.         waiting_for_masters--;
  3559.         if ( waiting_for_masters == 0)
  3560.         add_servers_from_masters();
  3561.     }
  3562.     if ( ! server_sort)
  3563.         display_server( server);
  3564.     }
  3565. }
  3566.  
  3567. void
  3568. get_next_timeout( struct timeval *timeout)
  3569. {
  3570.     struct qserver *server= servers;
  3571.     struct timeval now;
  3572.     int diff1, diff2, diff, smallest= retry_interval+master_retry_interval;
  3573.     int interval, bind_count= 0;
  3574.     static struct qserver *first_server_bind= NULL;
  3575.  
  3576.     if ( first_server_bind == NULL)
  3577.     first_server_bind= servers;
  3578.  
  3579.     server= first_server_bind;
  3580.  
  3581.     for ( ; server != NULL && server->fd == -1; server= server->next)
  3582.     ;
  3583.     if ( server == NULL)  {
  3584.     timeout->tv_sec= 0;
  3585.     timeout->tv_usec= 10 * 1000;
  3586.     return;
  3587.     }
  3588.     first_server_bind= server;
  3589.  
  3590.     gettimeofday( &now, NULL);
  3591.     for ( ; server != NULL && bind_count < connected; server= server->next)  {
  3592.     if ( server->fd == -1)
  3593.         continue;
  3594.     if ( server->type->id & MASTER_SERVER)
  3595.         interval= master_retry_interval;
  3596.     else
  3597.         interval= retry_interval;
  3598.     diff2= 0xffff;
  3599.     diff1= 0xffff;
  3600.     if ( server->server_name == NULL)
  3601.         diff1= interval*(n_retries-server->retry1+1) -
  3602.         time_delta( &now, &server->packet_time1);
  3603.     else  {
  3604.         if ( server->next_rule != NULL)
  3605.         diff1= interval*(n_retries-server->retry1+1) -
  3606.             time_delta( &now, &server->packet_time1);
  3607.         if ( server->next_player_info < server->num_players)
  3608.         diff2= interval*(n_retries-server->retry2+1) -
  3609.             time_delta( &now, &server->packet_time2);
  3610.     }
  3611.     diff= (diff1<diff2)?diff1:diff2;
  3612.     if ( diff < smallest)
  3613.         smallest= diff;
  3614.     bind_count++;
  3615.     }
  3616.     if ( smallest < 10)
  3617.     smallest= 10;
  3618.     timeout->tv_sec= smallest / 1000;
  3619.     timeout->tv_usec= (smallest % 1000) * 1000;
  3620. }
  3621.  
  3622.  
  3623. #ifdef USE_SELECT
  3624. static fd_set select_read_fds;
  3625. static int select_maxfd;
  3626. static int select_cursor;
  3627.  
  3628. int
  3629. set_fds( fd_set *fds)
  3630. {
  3631.     int maxfd= 1, i;
  3632.  
  3633.     for ( i= 0; i < max_connmap; i++)
  3634.     if ( connmap[i] != NULL)  {
  3635.         FD_SET( connmap[i]->fd, fds);
  3636.         if ( connmap[i]->fd > maxfd)
  3637.         maxfd= connmap[i]->fd;
  3638.     }
  3639.  
  3640.     return maxfd;
  3641. }
  3642.  
  3643. void
  3644. set_file_descriptors()
  3645. {
  3646.     FD_ZERO( &select_read_fds);
  3647.     select_maxfd= set_fds( &select_read_fds);
  3648. }
  3649.  
  3650. int
  3651. wait_for_file_descriptors( struct timeval *timeout)
  3652. {
  3653.     select_cursor= 0;
  3654.     return select( select_maxfd+1, &select_read_fds, NULL, NULL, timeout);
  3655. }
  3656.  
  3657. struct qserver *
  3658. get_next_ready_server()
  3659. {
  3660.     while ( select_cursor < max_connmap &&
  3661.         ( connmap[select_cursor] == NULL ||
  3662.         ! FD_ISSET( connmap[select_cursor]->fd, &select_read_fds)) )
  3663.     select_cursor++;
  3664.     if ( select_cursor >= max_connmap)
  3665.     return NULL;
  3666.     return connmap[select_cursor++];
  3667. }
  3668.  
  3669. int
  3670. wait_for_timeout( unsigned int ms)
  3671. {
  3672.     struct timeval timeout;
  3673.     timeout.tv_sec= ms/1000;
  3674.     timeout.tv_usec= (ms%1000) * 1000;
  3675.     return select( 0, 0, NULL, NULL, &timeout);
  3676. }
  3677.  
  3678. #endif /* USE_SELECT */
  3679.  
  3680. #ifdef USE_POLL
  3681. static struct pollfd *pollfds;
  3682. static int n_pollfds;
  3683. static int max_pollfds= 0;
  3684. static int poll_cursor;
  3685.  
  3686. void
  3687. set_file_descriptors()
  3688. {
  3689.     struct pollfd *p;
  3690.     int i;
  3691.  
  3692.     if ( max_connmap > max_pollfds)  {
  3693.     max_pollfds= max_connmap;
  3694.     pollfds= (struct pollfd *) realloc( pollfds, max_pollfds *
  3695.         sizeof(struct pollfd));
  3696.     }
  3697.  
  3698.     p= pollfds;
  3699.     for ( i= 0; i < max_connmap; i++)
  3700.     if ( connmap[i] != NULL)  {
  3701.         p->fd= connmap[i]->fd;
  3702.         p->events= POLLIN;
  3703.         p->revents= 0;
  3704.         p++;
  3705.     }
  3706.     n_pollfds= p - pollfds;
  3707. }
  3708.  
  3709. int
  3710. wait_for_file_descriptors( struct timeval *timeout)
  3711. {
  3712.     poll_cursor= 0;
  3713.     return poll( pollfds, n_pollfds, timeout->tv_sec*1000 + timeout->tv_usec/1000);
  3714. }
  3715.  
  3716. struct qserver *
  3717. get_next_ready_server()
  3718. {
  3719.     for ( ; poll_cursor < n_pollfds; poll_cursor++)
  3720.     if ( pollfds[ poll_cursor].revents)
  3721.         break;
  3722.     if ( poll_cursor >= n_pollfds)
  3723.     return NULL;
  3724.     return connmap[pollfds[poll_cursor++].fd];
  3725. }
  3726.  
  3727. int
  3728. wait_for_timeout( unsigned int ms)
  3729. {
  3730.     return poll( 0, 0, ms);
  3731. }
  3732.  
  3733. #endif /* USE_POLL */
  3734.  
  3735.  
  3736.  
  3737. /* Functions for handling response packets
  3738.  */
  3739.  
  3740. /* Packet from normal Quake server
  3741.  */
  3742. void
  3743. deal_with_q_packet( struct qserver *server, char *rawpkt, int pktlen)
  3744. {
  3745.     struct q_packet *pkt= (struct q_packet *)rawpkt;
  3746.     int rc;
  3747.  
  3748.     if ( ntohs( pkt->length) != pktlen)  {
  3749.     fprintf( stderr, "%s Ignoring bogus packet; length %d != %d\n",
  3750.         server->arg, ntohs( pkt->length), pktlen);
  3751.     cleanup_qserver(server,FORCE);
  3752.     return;
  3753.     }
  3754.  
  3755.     rawpkt[pktlen]= '\0';
  3756.  
  3757.     switch ( pkt->op_code)  {
  3758.     case Q_CCREP_ACCEPT:
  3759.     case Q_CCREP_REJECT:
  3760.     return;
  3761.     case Q_CCREP_SERVER_INFO:
  3762.     server->ping_total+= time_delta( &packet_recv_time,
  3763.         &server->packet_time1);
  3764.     rc= server_info_packet( server, pkt, pktlen-Q_HEADER_LEN);
  3765.     break;
  3766.     case Q_CCREP_PLAYER_INFO:
  3767.     server->ping_total+= time_delta( &packet_recv_time,
  3768.         &server->packet_time2);
  3769.     rc= player_info_packet( server, pkt, pktlen-Q_HEADER_LEN);
  3770.     break;
  3771.     case Q_CCREP_RULE_INFO:
  3772.     server->ping_total+= time_delta( &packet_recv_time,
  3773.         &server->packet_time1);
  3774.     rc= rule_info_packet( server, pkt, pktlen-Q_HEADER_LEN);
  3775.     break;
  3776.     case Q_CCREQ_CONNECT:
  3777.     case Q_CCREQ_SERVER_INFO:
  3778.     case Q_CCREQ_PLAYER_INFO:
  3779.     case Q_CCREQ_RULE_INFO:
  3780.     default:
  3781.     return;
  3782.     }
  3783.  
  3784.     if ( rc == -1)
  3785.     fprintf( stderr, "%s error on packet opcode %x\n", server->arg,
  3786.         (int)pkt->op_code);
  3787.  
  3788.     cleanup_qserver( server, (rc == -1) ? FORCE : 0);
  3789. }
  3790.  
  3791. /* Packet from QuakeWorld server
  3792.  */
  3793. void
  3794. deal_with_qw_packet( struct qserver *server, char *rawpkt, int pktlen)
  3795. {
  3796.     if ( server->server_name == NULL)
  3797.     server->ping_total+= time_delta( &packet_recv_time,
  3798.         &server->packet_time1);
  3799.  
  3800.     if ( ((rawpkt[0] != '\377' && rawpkt[0] != '\376') || rawpkt[1] != '\377' ||
  3801.         rawpkt[2] != '\377' || rawpkt[3] != '\377') && show_errors)  {
  3802.     unsigned int ipaddr= ntohl(server->ipaddr);
  3803.     fprintf( stderr,
  3804.         "Odd packet from server %d.%d.%d.%d:%hu, processing ...\n",
  3805.         (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
  3806.         (ipaddr>>8)&0xff, ipaddr&0xff, ntohs(server->port));
  3807.     print_packet( server, rawpkt, pktlen);
  3808.     }
  3809.  
  3810.     rawpkt[pktlen]= '\0';
  3811.  
  3812.     if ( rawpkt[4] == 'n')  {
  3813.     if ( server->type->id != QW_SERVER)
  3814.         server->type= find_server_type_id( QW_SERVER);
  3815.     deal_with_q1qw_packet( server, rawpkt, pktlen);
  3816.     return;
  3817.     }
  3818.     else if ( rawpkt[4] == '\377' && rawpkt[5] == 'n')  {
  3819.     if ( server->type->id != HW_SERVER)
  3820.         server->type= find_server_type_id( HW_SERVER);
  3821.     deal_with_q1qw_packet( server, rawpkt, pktlen);
  3822.     return;
  3823.     }
  3824.     else if ( strncmp( &rawpkt[4], "print\n\\", 7) == 0)  {
  3825.     deal_with_q2_packet( server, rawpkt+10, pktlen-10, 0);
  3826.     return;
  3827.     }
  3828.     else if ( strncmp( &rawpkt[4], "print\n", 6) == 0)  {
  3829.     /* work-around for occasional bug in Quake II status packets
  3830.     */
  3831.     char *c, *p;
  3832.     p= c= &rawpkt[10];
  3833.     while ( *p != '\\' && (c= strchr( p, '\n')))
  3834.         p= c+1;
  3835.     if ( *p == '\\' && c != NULL)  {
  3836.         deal_with_q2_packet( server, p, pktlen-(p-rawpkt), 0);
  3837.         return;
  3838.     }
  3839.     }
  3840.     else if ( strncmp( &rawpkt[4], "infoResponse", 12) == 0 ||
  3841.         (rawpkt[4] == '\001' && strncmp( &rawpkt[5], "infoResponse", 12) == 0) )  {
  3842.     /* quake3 info response */
  3843.     if ( rawpkt[4] == '\001')  {
  3844.         rawpkt++;
  3845.         pktlen--;
  3846.     }
  3847.     rawpkt+= 12;
  3848.     pktlen-= 12;
  3849.     for ( ; pktlen && *rawpkt != '\\'; pktlen--, rawpkt++)
  3850.         ;
  3851.     if ( !pktlen)
  3852.         return;
  3853.     if ( rawpkt[pktlen-1] == '"')  {
  3854.         rawpkt[pktlen-1]= '\0';
  3855.         pktlen--;
  3856.     }
  3857.     if ( get_player_info || get_server_rules)
  3858.         server->next_rule= "";
  3859.     deal_with_q2_packet( server, rawpkt, pktlen, 0);
  3860.     if ( (get_player_info || get_server_rules) && server->fd != -1)  {
  3861.         send_rule_request_packet( server);
  3862.         server->retry1= n_retries-1;
  3863.     }
  3864.     return;
  3865.     }
  3866.     else if ( strncmp( &rawpkt[4], "statusResponse\n", 15) == 0 ||
  3867.         (rawpkt[4] == '\001' && strncmp( &rawpkt[5], "statusResponse\n", 15) == 0) )  {
  3868.     /* quake3 status response */
  3869.     server->next_rule= NO_SERVER_RULES;
  3870.     server->next_player_info= server->max_players;
  3871.     if ( rawpkt[4] == '\001')  {
  3872.         rawpkt++;
  3873.         pktlen--;
  3874.     }
  3875.         deal_with_q2_packet( server, rawpkt + 19, pktlen - 19,
  3876.         CHECK_DUPLICATE_RULES);
  3877.     return;
  3878.     }
  3879.     else if ( strncmp( &rawpkt[4], "infostringresponse", 19) == 0)  {
  3880.     deal_with_q2_packet( server, rawpkt+23, pktlen-23, 0);
  3881.     return;
  3882.     }
  3883.  
  3884.     if ( show_errors)  {
  3885.     unsigned int ipaddr= ntohl(server->ipaddr);
  3886.     fprintf( stderr,
  3887.         "Odd packet from server %d.%d.%d.%d:%hu, ignoring ...\n",
  3888.         (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
  3889.         (ipaddr>>8)&0xff, ipaddr&0xff, ntohs(server->port));
  3890.     print_packet( server, rawpkt, pktlen);
  3891.     cleanup_qserver( server, 1);
  3892.     }
  3893.     else
  3894.     cleanup_qserver( server, 0);
  3895. }
  3896.  
  3897. void
  3898. deal_with_q1qw_packet( struct qserver *server, char *rawpkt, int pktlen)
  3899. {
  3900.     char *key, *value, *end;
  3901.     struct rule *rule;
  3902.     struct player *player= NULL, **last_player= &server->players;
  3903.     int len, rc, complete= 0;
  3904.     int number, frags, connect_time, ping;
  3905.     char *pkt= &rawpkt[5];
  3906.  
  3907.     if ( server->type->id == HW_SERVER)
  3908.     pkt= &rawpkt[6];
  3909.  
  3910.     while ( *pkt && pkt-rawpkt < pktlen)  {
  3911.     if ( *pkt == '\\')  {
  3912.         pkt++;
  3913.         end= strchr( pkt, '\\');
  3914.         if ( end == NULL)
  3915.         break;
  3916.         *end= '\0';
  3917.         key= pkt;
  3918.         pkt+= strlen(pkt)+1;
  3919.         end= strchr( pkt, '\\');
  3920.         if ( end == NULL)
  3921.         end= strchr( pkt, '\n');
  3922.         value= (char*) malloc(end-pkt+1);
  3923.         memcpy( value, pkt, end-pkt);
  3924.         value[end-pkt]= '\0';
  3925.         pkt= end;
  3926.         if ( strcmp( key, "hostname") == 0)
  3927.         server->server_name= value;
  3928.         else if  ( strcmp( key, "map") == 0)
  3929.         server->map_name= value;
  3930.         else if  ( strcmp( key, "maxclients") == 0)  {
  3931.         server->max_players= atoi(value);
  3932.         free( value);
  3933.         }
  3934.         else if ( get_server_rules || strncmp( key, "*game", 5) == 0)  {
  3935.         add_rule( server, key, value, NO_VALUE_COPY);
  3936.         if ( strcmp( key, "*gamedir") == 0)
  3937.             server->game= value;
  3938.         }
  3939.     }
  3940.     else if ( *pkt == '\n')  {
  3941.         pkt++;
  3942.         if ( pkt-rawpkt>=pktlen || *pkt == '\0')
  3943.         break;
  3944.         rc= sscanf( pkt, "%d %d %d %d %n", &number, &frags, &connect_time,
  3945.         &ping, &len);
  3946.         if ( rc != 4)  {
  3947.         char *nl;    /* assume it's an error packet */
  3948.         server->error= (char*)malloc( pktlen+1);
  3949.             nl= strchr( pkt, '\n');
  3950.         if ( nl != NULL)  {
  3951.             strncpy( server->error, pkt, nl-pkt);
  3952.             server->error[nl-pkt]= '\0';
  3953.         }
  3954.         else
  3955.             strcpy( server->error, pkt);
  3956.         server->server_name= SERVERERROR;
  3957.         complete= 1;
  3958.         break;
  3959.         }
  3960.         if ( get_player_info)  {
  3961.         player= (struct player *) calloc( 1, sizeof( struct player));
  3962.         player->number= number;
  3963.         player->frags= frags;
  3964.         player->connect_time= connect_time * 60;
  3965.         player->ping= ping;
  3966.         }
  3967.         else
  3968.         player= NULL;
  3969.  
  3970.         pkt+= len;
  3971.  
  3972.         if ( *pkt != '"') break;
  3973.         pkt++;
  3974.         end= strchr( pkt, '"');
  3975.         if ( end == NULL) break;
  3976.         if ( player != NULL)  {
  3977.         player->name= (char*) malloc(end-pkt+1);
  3978.         memcpy( player->name, pkt, end-pkt);
  3979.         player->name[end-pkt]= '\0';
  3980.         }
  3981.         pkt= end+2;
  3982.  
  3983.         if ( *pkt != '"') break;
  3984.         pkt++;
  3985.         end= strchr( pkt, '"');
  3986.         if ( end == NULL) break;
  3987.         if ( player != NULL)  {
  3988.         player->skin= (char*) malloc(end-pkt+1);
  3989.         memcpy( player->skin, pkt, end-pkt);
  3990.         player->skin[end-pkt]= '\0';
  3991.         }
  3992.         pkt= end+2;
  3993.  
  3994.         if ( player != NULL)  {
  3995.         sscanf( pkt, "%d %d%n", &player->shirt_color,
  3996.             &player->pants_color, &len);
  3997.         *last_player= player;
  3998.         last_player= & player->next;
  3999.         }
  4000.         else
  4001.         sscanf( pkt, "%*d %*d%n", &len);
  4002.         pkt+= len;
  4003.  
  4004.         server->num_players++;
  4005.     }
  4006.     else
  4007.         pkt++;
  4008.     complete= 1;
  4009.     }
  4010.  
  4011.     if ( !complete)  {
  4012.     if ( rawpkt[4] != 'n' || rawpkt[5] != '\0')  {
  4013.         fprintf( stderr,
  4014.         "Odd packet from QW server %d.%d.%d.%d:%hu ...\n",
  4015.         (server->ipaddr>>24)&0xff, (server->ipaddr>>16)&0xff,
  4016.         (server->ipaddr>>8)&0xff, server->ipaddr&0xff,
  4017.         ntohs(server->port));
  4018.         print_packet( server, rawpkt, pktlen);
  4019.     }
  4020.     }
  4021.     else if ( server->server_name == NULL)
  4022.     server->server_name= strdup("");
  4023.  
  4024.     cleanup_qserver( server, 0);
  4025. }
  4026.  
  4027. void
  4028. deal_with_q2_packet( struct qserver *server, char *rawpkt, int pktlen,
  4029.     int check_duplicate_rules)
  4030. {
  4031.     char *key, *value, *end;
  4032.     struct rule *rule;
  4033.     struct player *player= NULL;
  4034.     struct player **last_player= & server->players;
  4035.     int len, rc, complete= 0;
  4036.     int frags=0, ping=0, num_players= 0;
  4037.     char *pkt= rawpkt;
  4038.  
  4039.     while ( *pkt && pkt-rawpkt < pktlen)  {
  4040.     if ( *pkt == '\\')  {
  4041.         pkt++;
  4042.         if ( *pkt == '\n' && server->type->id == SOF_SERVER)
  4043.         goto player_info;
  4044.         end= strchr( pkt, '\\');
  4045.         if ( end == NULL)
  4046.         break;
  4047.         *end= '\0';
  4048.         key= pkt;
  4049.         pkt+= strlen(pkt)+1;
  4050.         end= strchr( pkt, '\\');
  4051.         if ( end == NULL)  {
  4052.         end= strchr( pkt, '\n');
  4053.         if ( end == NULL)
  4054.             end= rawpkt+pktlen;
  4055.         }
  4056.         value= (char*) malloc(end-pkt+1);
  4057.         memcpy( value, pkt, end-pkt);
  4058.         value[end-pkt]= '\0';
  4059.         pkt= end;
  4060.         if ( server->server_name == NULL &&
  4061.             (strcmp( key, "hostname") == 0 ||
  4062.             strcmp( key, "sv_hostname") == 0))
  4063.         server->server_name= value;
  4064.         else if  ( strcmp( key, "mapname") == 0 ||
  4065.             (strcmp( key, "map") == 0 && server->map_name == NULL))  {
  4066.         if ( server->map_name != NULL)
  4067.             free( server->map_name);
  4068.         server->map_name= value;
  4069.         }
  4070.         else if  ( strcmp( key, "maxclients") == 0 || 
  4071.                 strcmp( key, "sv_maxclients") == 0 ||
  4072.             strcmp( key, "max") == 0)  {
  4073.         if ( server->max_players == -1)
  4074.             server->next_player_info= atoi(value);
  4075.         server->max_players= atoi(value);
  4076.         /* MOHAA Q3 protocol max players is always 0 */
  4077.         if ( server->max_players == 0)
  4078.             server->max_players= -1;
  4079.         free(value);
  4080.         }
  4081.         else if  ( strcmp( key, "clients") == 0 ||
  4082.             strcmp( key, "players") == 0)  {
  4083.         server->num_players= atoi(value);
  4084.         free(value);
  4085.         }
  4086.         else if ( server->server_name == NULL &&
  4087.             strcmp( key, "pure") == 0)  {
  4088.         add_rule( server, key, value, NO_VALUE_COPY);
  4089.         }
  4090.         else if ( get_server_rules || strncmp( key, "game", 4) == 0)  {
  4091.         add_rule( server, key, value,
  4092.             NO_VALUE_COPY|check_duplicate_rules);
  4093.         if ( strcmp( key, server->type->game_rule) == 0)
  4094.             server->game= value;
  4095.         }
  4096.     }
  4097.     else if ( *pkt == '\n')  {
  4098. player_info:
  4099.         pkt++;
  4100.         if ( *pkt == '\0')
  4101.         break;
  4102.         rc= sscanf( pkt, "%d %n", &frags, &len);
  4103.         if ( rc == 1 && pkt[len] != '"')  {
  4104.         pkt+= len;
  4105.         rc= sscanf( pkt, "%d %n", &ping, &len);
  4106.         }
  4107.         else if ( rc == 1)  {
  4108.         /* MOHAA Q3 protocol only provides player ping */
  4109.         ping= frags;
  4110.         frags= 0;
  4111.         }
  4112.         if ( rc != 1)  {
  4113.         char *nl;    /* assume it's an error packet */
  4114.         server->error= (char*)malloc( pktlen+1);
  4115.             nl= strchr( pkt, '\n');
  4116.         if ( nl != NULL)
  4117.             strncpy( server->error, pkt, nl-pkt);
  4118.         else
  4119.             strcpy( server->error, pkt);
  4120.         server->server_name= SERVERERROR;
  4121.         complete= 1;
  4122.         break;
  4123.         }
  4124.         if ( get_player_info)  {
  4125.         player= (struct player *) calloc( 1, sizeof( struct player));
  4126.         player->number= 0;
  4127.         player->connect_time= -1;
  4128.         player->frags= frags;
  4129.         player->ping= ping;
  4130.         }
  4131.         else
  4132.         player= NULL;
  4133.  
  4134.         pkt+= len;
  4135.  
  4136.         if ( isdigit(*pkt))  {
  4137.         /* probably an SOF2 1.01 server, includes team # */
  4138.         int team;
  4139.         rc= sscanf( pkt, "%d %n", &team, &len);
  4140.         if ( rc == 1)  {
  4141.             pkt+= len;
  4142.             if ( player)  {
  4143.             player->team= team;
  4144.             server->flags|= FLAG_PLAYER_TEAMS;
  4145.             }
  4146.         }
  4147.         }
  4148.  
  4149.         if ( *pkt != '"') break;
  4150.  
  4151.         pkt++;
  4152.         end= strchr( pkt, '"');
  4153.         if ( end == NULL) break;
  4154.         if ( player != NULL)  {
  4155.         player->name= (char*) malloc(end-pkt+1);
  4156.         memcpy( player->name, pkt, end-pkt);
  4157.         player->name[end-pkt]= '\0';
  4158.         }
  4159.         pkt= end+1;
  4160.  
  4161.         if ( player != NULL)  {
  4162.         player->skin= NULL;
  4163.         player->shirt_color= -1;
  4164.         player->pants_color= -1;
  4165.         *last_player= player;
  4166.         last_player= & player->next;
  4167.         }
  4168.         num_players++;
  4169.     }
  4170.     else
  4171.         pkt++;
  4172.     complete= 1;
  4173.     }
  4174.  
  4175.     if ( server->num_players == 0 || num_players > server->num_players)
  4176.     server->num_players= num_players;
  4177.  
  4178.     if ( !complete)  {
  4179.     cleanup_qserver( server, 1);
  4180.     return;
  4181.     }
  4182.     else if ( server->server_name == NULL)
  4183.     server->server_name= strdup("");
  4184.  
  4185.     cleanup_qserver( server, 0);
  4186. }
  4187.  
  4188. void
  4189. ack_descent3master_packet( struct qserver *server, char *curtok )
  4190. {
  4191.     int rc;
  4192.     char packet[0x1e];
  4193.     memcpy( packet, descent3_masterquery,0x1a);
  4194.     packet[1]= 0x1d;
  4195.     packet[0x16]= 1;
  4196.     memcpy( packet + 0x1a, curtok, 4);
  4197.     rc= send( server->fd, packet, sizeof(packet), 0);
  4198.     if ( rc == SOCKET_ERROR)
  4199.     perror( "send");
  4200. }
  4201.  
  4202. /* Packet from Descent3 master server (PXO)
  4203.  */
  4204. void
  4205. deal_with_descent3master_packet( struct qserver *server, char *rawpkt, int pktlen)
  4206. {
  4207.     int i= 0, lastpacket= 0;
  4208.     char *names= rawpkt + 0x1f;
  4209.     char *ips= rawpkt + 0x29f;
  4210.     char *ports= rawpkt + 0x2ef;
  4211.     /* printf ("s=%p p=%p l=%i\n",server,rawpkt,pktlen); */
  4212.     while ( i<20) {
  4213.     if ( *names) {
  4214.         char *c;
  4215.         server->master_pkt_len += 6;
  4216.         server->master_pkt= (char*)realloc( server->master_pkt,
  4217.             server->master_pkt_len);
  4218.         c= server->master_pkt + server->master_pkt_len - 6;
  4219.         memcpy( c, ips, 4);
  4220.         memcpy( c + 4, ports, 2);
  4221.     }else if (i>0)
  4222.         lastpacket= 1;
  4223.     names+= 0x20;
  4224.     ips+= 4;
  4225.     ports+= 2;
  4226.     i++;
  4227.     }
  4228.  
  4229.     ack_descent3master_packet( server, rawpkt+0x1a);
  4230.  
  4231.     server->n_servers= server->master_pkt_len / 6;
  4232.     
  4233.     server->next_player_info= -1;
  4234.     server->retry1= 0;
  4235.     
  4236.     if (lastpacket) {
  4237.     cleanup_qserver( server, 0);
  4238.     }
  4239. }
  4240.  
  4241. /* Packet from QuakeWorld master server
  4242.  */
  4243. void
  4244. deal_with_qwmaster_packet( struct qserver *server, char *rawpkt, int pktlen)
  4245. {
  4246.     server->ping_total+= time_delta( &packet_recv_time,
  4247.         &server->packet_time1);
  4248.  
  4249.     if ( rawpkt[0] == QW_NACK)  {
  4250.     server->error= strdup( &rawpkt[2]);
  4251.     server->server_name= SERVERERROR;
  4252.     cleanup_qserver( server, 1);
  4253.     return;
  4254.     }
  4255.  
  4256.     if ( *((unsigned int*)rawpkt) == 0xffffffff)  {
  4257.     rawpkt+= 4;    /* QW 1.5 */
  4258.     pktlen-= 4;
  4259.     }
  4260.  
  4261.     if ( rawpkt[0] == QW_SERVERS && rawpkt[1] == QW_NEWLINE)  {
  4262.     rawpkt+= 2;
  4263.     pktlen-= 2;
  4264.     }
  4265.     else if ( rawpkt[0] == HL_SERVERS && rawpkt[1] == 0x0d)  {
  4266.     memcpy( server->master_query_tag, rawpkt+2, 3);
  4267.     rawpkt+= 6;
  4268.     pktlen-= 6;
  4269.     }
  4270.     else if ( strncmp( rawpkt, "servers", 7) == 0)  {
  4271.     rawpkt+= 8;
  4272.     pktlen-= 8;
  4273.     }
  4274.     else if ( strncmp( rawpkt, "getserversResponse", 18) == 0)  {
  4275.         char *p;
  4276.     static int q3m_debug= 0;
  4277.  
  4278.     rawpkt+= 18;
  4279.     pktlen-= 18;
  4280.  
  4281.     for ( ; *rawpkt != '\\' && pktlen; pktlen--, rawpkt++)
  4282.         ;
  4283.     if ( !pktlen)
  4284.         return;
  4285.     rawpkt++;
  4286.     pktlen--;
  4287.  
  4288. if ( q3m_debug) printf( "q3m pktlen %d lastchar %x\n", pktlen, (unsigned int)rawpkt[pktlen-1]);
  4289.     server->master_pkt= (char*)realloc( server->master_pkt,
  4290.         server->master_pkt_len + pktlen+1);
  4291.  
  4292.     if ( server->type->id == STEF_MASTER)
  4293.         decode_stefmaster_packet( server, rawpkt, pktlen);
  4294.     else
  4295.         decode_q3master_packet( server, rawpkt, pktlen);
  4296. if ( q3m_debug) printf( "q3m %d servers\n", server->n_servers);
  4297.  
  4298.     return;
  4299.     }
  4300.     else if ( show_errors)  {
  4301.     unsigned int ipaddr= ntohl(server->ipaddr);
  4302.     fprintf( stderr,
  4303.         "Odd packet from QW master %d.%d.%d.%d, processing ...\n",
  4304.         (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
  4305.         (ipaddr>>8)&0xff, ipaddr&0xff);
  4306.     print_packet( server, rawpkt, pktlen);
  4307.     }
  4308.  
  4309.     server->master_pkt= (char*)realloc( server->master_pkt,
  4310.     server->master_pkt_len+pktlen+1);
  4311.     rawpkt[pktlen]= '\0';
  4312.     memcpy( server->master_pkt+server->master_pkt_len, rawpkt, pktlen+1);
  4313.     server->master_pkt_len+= pktlen;
  4314.  
  4315.     server->n_servers= server->master_pkt_len / 6;
  4316.  
  4317.     if ( server->type->flags & TF_MASTER_MULTI_RESPONSE)  {
  4318.     server->next_player_info= -1;
  4319.     server->retry1= 0;
  4320.     }
  4321.     else if ( server->type->id == HL_MASTER)  {
  4322.     if ( server->master_query_tag[0] == 0 &&
  4323.         server->master_query_tag[1] == 0 &&
  4324.         server->master_query_tag[2] == 0)  {
  4325.         server->server_name= MASTER;
  4326.         cleanup_qserver( server, 1);
  4327.         bind_sockets();
  4328.     }
  4329.     else  {
  4330.         server->retry1++;
  4331.         send_qwmaster_request_packet( server);
  4332.     }
  4333.     }
  4334.     else  {
  4335.     server->server_name= MASTER;
  4336.     cleanup_qserver( server, 0);
  4337.     bind_sockets();
  4338.     }
  4339. }
  4340.  
  4341. void
  4342. decode_q3master_packet( struct qserver *server, char *pkt, int pktlen)
  4343. {
  4344.     char *p;
  4345.  
  4346.     pkt[pktlen]= 0;
  4347.     p= pkt;
  4348.  
  4349.     while ( *p && p < &pkt[pktlen-6]) {
  4350.     memcpy( server->master_pkt + server->master_pkt_len, &p[0], 4);
  4351.     memcpy( server->master_pkt + server->master_pkt_len + 4, &p[4], 2);
  4352.     server->master_pkt_len += 6;
  4353.     p+= 6;
  4354.     while ( *p && *p == '\\')
  4355.         p++;
  4356.     }
  4357.     server->n_servers= server->master_pkt_len / 6;
  4358.     server->next_player_info= -1;
  4359.     server->retry1= 0;
  4360. }
  4361.  
  4362. void
  4363. decode_stefmaster_packet( struct qserver *server, char *pkt, int pktlen)
  4364. {
  4365.     unsigned char *p, *m, *end;
  4366.     unsigned int i, b;
  4367.  
  4368.     pkt[pktlen]= 0;
  4369.  
  4370.     p= (unsigned char*) pkt;
  4371.     m= (unsigned char*) server->master_pkt + server->master_pkt_len;
  4372.     end= (unsigned char*) &pkt[pktlen-12];
  4373.     while ( *p && p < end)  {
  4374.     for ( i= 6; i; i--)  {
  4375.         sscanf( (char*)p, "%2x", &b);
  4376.         p+= 2;
  4377.         *m++= b;
  4378.     }
  4379.     server->master_pkt_len += 6;
  4380.     while ( *p && *p == '\\')
  4381.         p++;
  4382.     }
  4383.     server->n_servers= server->master_pkt_len / 6;
  4384.     server->next_player_info= -1;
  4385.     server->retry1= 0;
  4386. }
  4387.  
  4388. /* Packet from Tribes master server
  4389.  */
  4390. void
  4391. deal_with_tribesmaster_packet( struct qserver *server, char *rawpkt, int pktlen)
  4392. {
  4393.     unsigned char *upkt= (unsigned char*) rawpkt;
  4394.     int packet_number= upkt[2];
  4395.     int n_packets= upkt[3];
  4396.     unsigned char *p;
  4397.     char *mpkt;
  4398.     int len;
  4399.     unsigned int ipaddr;
  4400.  
  4401.     if ( memcmp( rawpkt, tribes_master_response, sizeof(tribes_master_response)) != 0)  {
  4402.     fprintf( stderr, "Odd packet from Tribes master server\n");
  4403.     print_packet( server, rawpkt, pktlen);
  4404.     }
  4405.  
  4406.     /* 0x1006
  4407.        01        packet number
  4408.        08        # packets
  4409.        02
  4410.        0000
  4411.        66
  4412.        0d        length of following string
  4413.        "Tribes Master"
  4414.        3c        length of following string
  4415.        "Check out the Starsiege demo now!   www.starsiegeplayers.com"
  4416.        0035
  4417.        06 d143 4764 812c
  4418.        06 d1e2 8df3 616d
  4419.        06 1804 6d50 616d
  4420.        06 d81c 6dc0 616d
  4421. */
  4422. /* 0x1006
  4423.    02
  4424.    08
  4425.    02 0000
  4426.    66
  4427.    00 3f
  4428.    06 cf88 344c 1227
  4429. */
  4430.  
  4431. /* printf( "packet_number %d n_packets %d\n", packet_number, n_packets);
  4432. */
  4433.  
  4434.     len= upkt[8];
  4435.     if ( len > 0)  {
  4436.     p= (unsigned char*) rawpkt+9;
  4437. /* printf( "%.*s\n", len, p);
  4438. */
  4439.     p+= len;
  4440.     len= upkt[8+len+1];
  4441. /* printf( "%.*s\n", len, p+1);
  4442. */
  4443.     p+= len+1;
  4444.     p+= 2;
  4445.     }
  4446.     else
  4447.     p= (unsigned char*) rawpkt+10;
  4448.  
  4449.     if ( server->master_pkt == NULL)  {
  4450.     server->master_pkt= (char*)malloc( n_packets*64*6);
  4451.     mpkt= server->master_pkt;
  4452.     }
  4453.     else
  4454.     mpkt= server->master_pkt + server->n_servers*6;
  4455.  
  4456.     while ( (char*)p < rawpkt+pktlen)  {
  4457.     if ( *p != 0x6) printf( "*p %u\n", (unsigned)*p);
  4458.     memcpy( mpkt, p+1, sizeof(ipaddr));
  4459.     if ( 0)  {
  4460.         mpkt[4]= p[5];
  4461.         mpkt[5]= p[6];
  4462.     }
  4463.     else  {
  4464.         mpkt[5]= p[5];
  4465.         mpkt[4]= p[6];
  4466.     }
  4467. /*
  4468.     printf( "%08x:%hu %u.%u.%u.%u:%hu\n", ipaddr, port, ipaddr>>24,
  4469.     (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff, port);
  4470. */
  4471.     p+= 7;
  4472.     mpkt+= 6;
  4473.     }
  4474. /*
  4475. if (  (char*)p != rawpkt+pktlen)
  4476. printf( "%x %x\n", p, rawpkt+pktlen);
  4477. */
  4478.     server->master_pkt_len= mpkt - server->master_pkt;
  4479.     server->n_servers= server->master_pkt_len / 6;
  4480.     server->server_name= MASTER;
  4481.     server->next_player_info= -1;
  4482.  
  4483.     if ( packet_number >= n_packets)
  4484.     cleanup_qserver( server, 1);
  4485.     else
  4486.     cleanup_qserver( server, 0);
  4487. }
  4488.  
  4489. char *
  4490. display_tribes2_string_list( unsigned char *pkt)
  4491. {
  4492.     char *delim="";
  4493.     unsigned int count, len;
  4494.     count= *pkt;
  4495.     pkt++;
  4496.     for ( ; count; count--)  {
  4497.     len= *pkt;
  4498.     pkt++;
  4499.     if ( len > 0)  {
  4500.         if ( raw_display)  {
  4501.         fprintf( OF, "%s%.*s", delim, len, pkt);
  4502.         delim= raw_delimiter;
  4503.         }
  4504.         else
  4505.         fprintf( OF, "%.*s\n", len, pkt);
  4506.     }
  4507.     pkt+= len;
  4508.     }
  4509.     if ( raw_display)
  4510.     fputs( "\n", OF);
  4511.     return (char*)pkt;
  4512. }
  4513.  
  4514. void
  4515. deal_with_tribes2master_packet( struct qserver *server, char *pkt, int pktlen)
  4516. {
  4517.     unsigned int n_servers, index, total, server_limit;
  4518.     char *p, *mpkt;
  4519.  
  4520.     if ( pkt[0] == TRIBES2_RESPONSE_GAME_TYPES)  {
  4521.     pkt+= 6;
  4522.     if ( raw_display)  {
  4523.         fprintf( OF, "%s%s%s%s", server->type->type_prefix, raw_delimiter,
  4524.         server->arg, raw_delimiter);
  4525.     }
  4526.     else  {
  4527.         fprintf( OF, "Game Types\n");
  4528.         fprintf( OF, "----------\n");
  4529.     }
  4530.     pkt= display_tribes2_string_list( (unsigned char *)pkt);
  4531.     if ( raw_display)  {
  4532.         fprintf( OF, "%s%s%s%s", server->type->type_prefix, raw_delimiter,
  4533.         server->arg, raw_delimiter);
  4534.     }
  4535.     else  {
  4536.         fprintf( OF, "\nMission Types\n");
  4537.         fprintf( OF, "-------------\n");
  4538.     }
  4539.     display_tribes2_string_list( (unsigned char *)pkt);
  4540.  
  4541.     server->master_pkt_len= 0;
  4542.     server->n_servers= 0;
  4543.     server->server_name= MASTER;
  4544.     server->next_player_info= -1;
  4545.     cleanup_qserver( server, 1);
  4546.     return;
  4547.     }
  4548.  
  4549.     if ( pkt[0] != TRIBES2_RESPONSE_MASTER)  {
  4550.     /* error */
  4551.     cleanup_qserver( server, 1);
  4552.     }
  4553.  
  4554.     server_limit= get_param_ui_value( server, "limit", ~0);
  4555.  
  4556.     n_servers= little_endian ? *(unsigned short*)(pkt+8) :
  4557.     swap_short(pkt+8);
  4558.     index= *(unsigned char*)(pkt+6);
  4559.     total= *(unsigned char*)(pkt+7);
  4560.     if ( server->master_pkt == NULL)  {
  4561.     server->master_pkt= (char*)malloc( total * n_servers * 6);
  4562.     mpkt= server->master_pkt;
  4563.     }
  4564.     else
  4565.     mpkt= server->master_pkt + server->n_servers*6;
  4566.  
  4567.     p= pkt+10;
  4568.     for ( ; n_servers && ((char*)mpkt - server->master_pkt)/6 < server_limit;
  4569.         n_servers--, p+= 6, mpkt+= 6)  {
  4570.     memcpy( mpkt, p, 4);
  4571.     mpkt[4]= p[5];
  4572.     mpkt[5]= p[4];
  4573.     }
  4574.     server->master_pkt_len= (char*)mpkt - server->master_pkt;
  4575.     server->n_servers= server->master_pkt_len / 6;
  4576.     server->server_name= MASTER;
  4577.     server->next_player_info= -1;
  4578.  
  4579.     if ( index >= total-1 || server->n_servers >= server_limit)
  4580.     cleanup_qserver( server, 1);
  4581.     else
  4582.     cleanup_qserver( server, 0);
  4583. }
  4584.  
  4585. int
  4586. server_info_packet( struct qserver *server, struct q_packet *pkt, int datalen)
  4587. {
  4588.     int off= 0;
  4589.  
  4590.     /* ignore duplicate packets */
  4591.     if ( server->server_name != NULL)
  4592.     return 0;
  4593.  
  4594.     server->address= strdup((char*)&pkt->data[off]);
  4595.     off+= strlen(server->address) + 1;
  4596.     if ( off >= datalen)
  4597.     return -1;
  4598.  
  4599.     server->server_name= strdup((char*)&pkt->data[off]);
  4600.     off+= strlen(server->server_name) + 1;
  4601.     if ( off >= datalen)
  4602.     return -1;
  4603.  
  4604.     server->map_name= strdup((char*)&pkt->data[off]);
  4605.     off+= strlen(server->map_name) + 1;
  4606.     if ( off > datalen)
  4607.     return -1;
  4608.  
  4609.     server->num_players= pkt->data[off++];
  4610.     server->max_players= pkt->data[off++];
  4611.     server->protocol_version= pkt->data[off++];
  4612.  
  4613.     server->retry1= n_retries;
  4614.  
  4615.     if ( get_server_rules)
  4616.     send_rule_request_packet( server);
  4617.     if ( get_player_info)
  4618.     send_player_request_packet( server);
  4619.  
  4620.     return 0;
  4621. }
  4622.  
  4623. int
  4624. player_info_packet( struct qserver *server, struct q_packet *pkt, int datalen)
  4625. {
  4626.     char *name, *address;
  4627.     int off, colors, frags, connect_time, player_number;
  4628.     struct player *player, *last;
  4629.  
  4630.     off= 0;
  4631.     player_number= pkt->data[off++];
  4632.     name= (char*) &pkt->data[off];
  4633.     off+= strlen(name)+1;
  4634.     if ( off >= datalen)
  4635.     return -1;
  4636.  
  4637.     colors= pkt->data[off+3];
  4638.     colors= (colors<<8) + pkt->data[off+2];
  4639.     colors= (colors<<8) + pkt->data[off+1];
  4640.     colors= (colors<<8) + pkt->data[off];
  4641.     off+= sizeof(colors);
  4642.  
  4643.     frags= pkt->data[off+3];
  4644.     frags= (frags<<8) + pkt->data[off+2];
  4645.     frags= (frags<<8) + pkt->data[off+1];
  4646.     frags= (frags<<8) + pkt->data[off];
  4647.     off+= sizeof(frags);
  4648.  
  4649.     connect_time= pkt->data[off+3];
  4650.     connect_time= (connect_time<<8) + pkt->data[off+2];
  4651.     connect_time= (connect_time<<8) + pkt->data[off+1];
  4652.     connect_time= (connect_time<<8) + pkt->data[off];
  4653.     off+= sizeof(connect_time);
  4654.  
  4655.     address= (char*) &pkt->data[off];
  4656.     off+= strlen(address)+1;
  4657.     if ( off > datalen)
  4658.     return -1;
  4659.  
  4660.     last= server->players;
  4661.     while ( last != NULL && last->next != NULL)  {
  4662.     if ( last->number == player_number)
  4663.          return 0;
  4664.     last= last->next;
  4665.     }
  4666.     if ( last != NULL && last->number == player_number)
  4667.     return 0;
  4668.  
  4669.     player= (struct player *) calloc( 1, sizeof(struct player));
  4670.     player->number= player_number;
  4671.     player->name= strdup( name);
  4672.     player->address= strdup( address);
  4673.     player->connect_time= connect_time;
  4674.     player->frags= frags;
  4675.     player->shirt_color= colors>>4;
  4676.     player->pants_color= colors&0xf;
  4677.     player->next= NULL;
  4678.  
  4679.     if ( last == NULL)
  4680.     server->players= player;
  4681.     else
  4682.     last->next= player;
  4683.  
  4684.     server->next_player_info++;
  4685.     server->retry2= n_retries;
  4686.     if ( server->next_player_info < server->num_players)
  4687.     send_player_request_packet( server);
  4688.  
  4689.     return 0;
  4690. }
  4691.  
  4692. int
  4693. rule_info_packet( struct qserver *server, struct q_packet *pkt, int datalen)
  4694. {
  4695.     int off= 0;
  4696.     struct rule *rule, *last;
  4697.     char *name, *value;
  4698.  
  4699.     /* Straggler packet after we've already given up fetching rules */
  4700.     if ( server->next_rule == NULL)
  4701.     return 0;
  4702.  
  4703.     if ( ntohs(pkt->length) == Q_HEADER_LEN)  {
  4704.     server->next_rule= NULL;
  4705.     return 0;
  4706.     }
  4707.  
  4708.     name= (char*)&pkt->data[off];
  4709.     off+= strlen( name)+1;
  4710.     if ( off >= datalen)
  4711.     return -1;
  4712.  
  4713.     value= (char*)&pkt->data[off];
  4714.     off+= strlen( value)+1;
  4715.     if ( off > datalen)
  4716.     return -1;
  4717.  
  4718.     last= server->rules;
  4719.     while ( last != NULL && last->next != NULL)  {
  4720.     if ( strcmp( last->name, name) == 0)
  4721.          return 0;
  4722.     last= last->next;
  4723.     }
  4724.     if ( last != NULL && strcmp( last->name, name) == 0)
  4725.     return 0;
  4726.  
  4727.     rule= (struct rule *) malloc( sizeof( struct rule));
  4728.     rule->name= strdup( name);
  4729.     rule->value= strdup( value);
  4730.     rule->next= NULL;
  4731.  
  4732.     if ( last == NULL)
  4733.     server->rules= rule;
  4734.     else
  4735.     last->next= rule;
  4736.  
  4737.     server->n_rules++;
  4738.     server->next_rule= rule->name;
  4739.     server->retry1= n_retries;
  4740.     send_rule_request_packet( server);
  4741.  
  4742.     return 0;
  4743. }
  4744.  
  4745. struct rule *
  4746. add_rule( struct qserver *server, char *key, char *value, int flags) 
  4747. {
  4748.     struct rule *rule;
  4749.     if ( flags & CHECK_DUPLICATE_RULES)  {
  4750.     for ( rule= server->rules; rule; rule= rule->next)
  4751.         if ( strcmp( rule->name, key) == 0)
  4752.             return rule;
  4753.     }
  4754.  
  4755.     rule= (struct rule *) malloc( sizeof( struct rule));
  4756.     rule->name= strdup(key);
  4757.     if ( flags & NO_VALUE_COPY)
  4758.     rule->value= value;
  4759.     else
  4760.     rule->value= strdup(value);
  4761.     rule->next= NULL;
  4762.     *server->last_rule= rule;
  4763.     server->last_rule= & rule->next;
  4764.     server->n_rules++;
  4765.     return rule;
  4766. }
  4767.  
  4768. void
  4769. add_nrule( struct qserver *server, char *key, char *value, int len) 
  4770. {
  4771.     struct rule *rule;
  4772.     for ( rule= server->rules; rule; rule= rule->next)
  4773.     if ( strcmp( rule->name, key) == 0)
  4774.         return;
  4775.  
  4776.     rule= (struct rule *) malloc( sizeof( struct rule));
  4777.     rule->name= strdup(key);
  4778.     rule->value= strndup(value,len);
  4779.     rule->next= NULL;
  4780.     *server->last_rule= rule;
  4781.     server->last_rule= & rule->next;
  4782.     server->n_rules++;
  4783. }
  4784.  
  4785. struct player *
  4786. add_player( struct qserver *server, int player_number)
  4787. {
  4788.     struct player *player;
  4789.     for ( player= server->players; player; player= player->next)
  4790.     if ( player->number == player_number)
  4791.         return NULL;
  4792.  
  4793.     player= (struct player *) calloc( 1, sizeof( struct player));
  4794.     player->number= player_number;
  4795.     player->next= server->players;
  4796.     server->players= player;
  4797.     return player;
  4798. }
  4799.  
  4800. void
  4801. deal_with_unreal_packet( struct qserver *server, char *rawpkt, int pktlen)
  4802. {
  4803.     char *s, *key, *value, *end;
  4804.     struct player *player= NULL;
  4805.     int id_major, id_minor, final=0;
  4806.  
  4807. server->n_servers++;
  4808.     if ( server->server_name == NULL)
  4809.     server->ping_total+= time_delta( &packet_recv_time,
  4810.         &server->packet_time1);
  4811.     else
  4812.     gettimeofday( &server->packet_time1, NULL);
  4813.  
  4814.     rawpkt[pktlen]= '\0';
  4815.     end= &rawpkt[pktlen];
  4816.  
  4817.     s= rawpkt;
  4818.     while ( *s)  {
  4819.     while ( *s == '\\') s++;
  4820.     if ( !*s) break;
  4821.     key= s;
  4822.     while ( *s && *s != '\\') s++;
  4823.     if ( !*s) break;
  4824.     *s++= '\0';
  4825.  
  4826. /*
  4827.     while ( *s == '\\') s++;
  4828.     if ( !*s)
  4829.         value= NULL;
  4830.     else
  4831.         value= s;
  4832. */
  4833.     value= s;
  4834.     while ( *s && *s != '\\') s++;
  4835.     if ( s[1] && !isalpha(s[1]))  {
  4836.         s++;
  4837.         while ( *s && *s != '\\') s++;
  4838.     }
  4839.     else if ( s[1] && isalpha(s[1]) &&
  4840.         strncmp( key, "player_", 7) == 0)  {
  4841.         if ( ! unreal_player_info_key( s+1, end))  {
  4842.         s++;
  4843.         while ( *s && *s != '\\') s++;
  4844.         }
  4845.     }
  4846.     if ( *s)
  4847.         *s++= '\0';
  4848.  
  4849.     if ( *value == '\0')  {
  4850.         if ( strcmp( key, "final") == 0)  {
  4851.         final= 1;
  4852.         continue;
  4853.         }
  4854.     }
  4855.  
  4856.     if ( strcmp( key, "mapname") == 0 && !server->map_name)
  4857.         server->map_name= strdup( value);
  4858.     else if ( strcmp( key, "hostname") == 0 && !server->server_name)
  4859.         server->server_name= strdup( value);
  4860.     else if ( strcmp( key, "maxplayers") == 0)
  4861.         server->max_players= atoi( value);
  4862.     else if ( strcmp( key, "numplayers") == 0)
  4863.         server->num_players= atoi( value);
  4864.     else if ( strcmp( key, server->type->game_rule) == 0 && !server->game) {
  4865.         server->game= strdup( value);
  4866.         add_rule( server, key, value, NO_FLAGS);
  4867.     }
  4868.     else if ( strcmp( key, "queryid") == 0)
  4869.         sscanf( value, "%d.%d", &id_major, &id_minor);
  4870.     else if ( strcmp( key, "final") == 0)  {
  4871.         final= 1;
  4872.         continue;
  4873.     }
  4874.     else if ( strncmp( key, "player_", 7) == 0)  {
  4875.         player= add_player( server, atoi(key+7));
  4876.         if ( player) 
  4877.         player->name= strdup( value);
  4878.     }
  4879.     else if ( player && strncmp( key, "frags_", 6) == 0)
  4880.         player->frags= atoi( value);
  4881.     else if ( player && strncmp( key, "team_", 5) == 0)
  4882.         player->team= atoi( value);
  4883.     else if ( player && strncmp( key, "skin_", 5) == 0)
  4884.         player->skin= strdup( value);
  4885.     else if ( player && strncmp( key, "mesh_", 5) == 0)
  4886.         player->mesh= strdup( value);
  4887.     else if ( player && strncmp( key, "ping_", 5) == 0)
  4888.         player->ping= atoi( value);
  4889.     else if ( player && strncmp( key, "face_", 5) == 0)
  4890.         player->face= strdup( value);
  4891.     else if ( player && strncmp( key, "deaths_", 7) == 0)
  4892.         player->deaths= atoi( value);
  4893.     else  {
  4894.         player= NULL;
  4895.         add_rule( server, key, value, NO_FLAGS);
  4896.     }
  4897.     }
  4898.  
  4899.     if ( final)
  4900.     cleanup_qserver( server, 1);
  4901.     if ( server->num_players < 0 && id_minor >= 3)
  4902.     cleanup_qserver( server, 1);
  4903. }
  4904.  
  4905. STATIC int
  4906. unreal_player_info_key( char *s, char *end)
  4907. {
  4908.     static char *keys[] = {"frags_", "team_", "ping_", "species_"};
  4909.     int i;
  4910.  
  4911.     for  ( i= 0; i < sizeof(keys)/sizeof(char*); i++)  {
  4912.     int len= strlen(keys[i]);
  4913.     if ( s+len < end && strncmp( s, keys[i], len) == 0)
  4914.         return 1;
  4915.     }
  4916.     return 0;
  4917. }
  4918.  
  4919. int
  4920. deal_with_unrealmaster_packet( struct qserver *server, char *rawpkt, int pktlen)
  4921. {
  4922.     if ( pktlen == 0)  {
  4923.     cleanup_qserver( server, 1);
  4924.     return 0;
  4925.     }
  4926.     print_packet( server, rawpkt, pktlen);
  4927. puts( "--");
  4928.     return 0;
  4929. }
  4930.  
  4931. void
  4932. deal_with_halflife_packet( struct qserver *server, char *rawpkt, int pktlen)
  4933. {
  4934.     char *pkt;
  4935.     char *end= &rawpkt[pktlen];
  4936.     int pkt_index= 0, pkt_max= 0;
  4937.     char number[16];
  4938.     short pkt_id;
  4939.  
  4940.     if ( server->server_name == NULL)
  4941.     server->ping_total+= time_delta( &packet_recv_time,
  4942.         &server->packet_time1);
  4943.  
  4944.     if ( pktlen < 5)  {
  4945.     cleanup_qserver( server, 1);
  4946.     return;
  4947.     }
  4948.  
  4949.     if ( ((rawpkt[0] != '\377' && rawpkt[0] != '\376') || rawpkt[1] != '\377' ||
  4950.         rawpkt[2] != '\377' || rawpkt[3] != '\377') && show_errors)  {
  4951.     unsigned int ipaddr= ntohl(server->ipaddr);
  4952.     fprintf( stderr,
  4953.         "Odd packet from server %d.%d.%d.%d:%hu, processing ...\n",
  4954.         (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
  4955.         (ipaddr>>8)&0xff, ipaddr&0xff, ntohs(server->port));
  4956.     print_packet( server, rawpkt, pktlen);
  4957.     }
  4958.  
  4959.     if ( ((unsigned char*)rawpkt)[0] == 0xfe)  {
  4960.     SavedData *sdata;
  4961.     pkt_index= ((unsigned char*)rawpkt)[8] >> 4;
  4962.     pkt_max= ((unsigned char*)rawpkt)[8] & 0xf;
  4963.     memcpy( &pkt_id, &rawpkt[4], 2);
  4964.  
  4965.     if ( server->saved_data.data == NULL)
  4966.         sdata= & server->saved_data;
  4967.     else  {
  4968.         sdata= (SavedData*) calloc( 1, sizeof(SavedData));
  4969.         sdata->next= server->saved_data.next;
  4970.         server->saved_data.next= sdata;
  4971.     }
  4972.  
  4973.     sdata->pkt_index= pkt_index;
  4974.     sdata->pkt_max= pkt_max;
  4975.     sdata->pkt_id= pkt_id;
  4976.     sdata->datalen= pktlen-9;
  4977.     sdata->data= (char*) malloc( pktlen-9);
  4978.     memcpy( sdata->data, &rawpkt[9], pktlen-9);
  4979.  
  4980.     /* combine_packets will call us recursively */
  4981.     combine_packets( server);
  4982.     return;
  4983.  
  4984. /*
  4985. fprintf( OF, "pkt_index %d pkt_max %d\n", pkt_index, pkt_max);
  4986.     rawpkt+= 9;
  4987.     pktlen-= 9;
  4988. */
  4989.     }
  4990.  
  4991.     /* 'info' response */
  4992.     if ( rawpkt[4] == 'C' || rawpkt[4] == 'm')  {
  4993.     if ( server->server_name != NULL)
  4994.         return;
  4995.     pkt= &rawpkt[5];
  4996.     server->address= strdup( pkt);
  4997.     pkt+= strlen(pkt)+1;
  4998.     server->server_name= strdup( pkt);
  4999.     pkt+= strlen(pkt)+1;
  5000.     server->map_name= strdup( pkt);
  5001.     pkt+= strlen(pkt)+1;
  5002.  
  5003.     if ( *pkt)
  5004.         add_rule( server, "gamedir", pkt, NO_FLAGS);
  5005.     if ( *pkt && strcmp( pkt, "valve") != 0)
  5006.         server->game= add_rule( server, "game", pkt, NO_FLAGS)->value;
  5007.     pkt+= strlen(pkt)+1;
  5008.     if ( *pkt)
  5009.         add_rule( server, "gamename", pkt, NO_FLAGS);
  5010.     pkt+= strlen(pkt)+1;
  5011.  
  5012.     server->num_players= (unsigned int)pkt[0];
  5013.     server->max_players= (unsigned int)pkt[1];
  5014.     pkt+= 2;
  5015.     if ( pkt < end)  {
  5016.         int protocol= *((unsigned char *)pkt);
  5017.         sprintf( number, "%d", protocol);
  5018.         add_rule( server, "protocol", number, NO_FLAGS);
  5019.         pkt++;
  5020.     }
  5021.  
  5022.     if ( rawpkt[4] == 'm')  {
  5023.         if ( *pkt == 'd')
  5024.         add_rule( server, "sv_type", "dedicated", NO_FLAGS);
  5025.         else if ( *pkt == 'l')
  5026.         add_rule( server, "sv_type", "listen", NO_FLAGS);
  5027.         else
  5028.         add_rule( server, "sv_type", "?", NO_FLAGS);
  5029.         pkt++;
  5030.         if ( *pkt == 'w')
  5031.         add_rule( server, "sv_os", "windows", NO_FLAGS);
  5032.         else if ( *pkt == 'l')
  5033.         add_rule( server, "sv_os", "linux", NO_FLAGS);
  5034.         else  {
  5035.         char str[2]= "\0";
  5036.         str[0]= *pkt;
  5037.         add_rule( server, "sv_os", str, NO_FLAGS);
  5038.         }
  5039.         pkt++;
  5040.         add_rule( server, "sv_password", *pkt ? "1" : "0", NO_FLAGS);
  5041.         pkt++;
  5042.         add_rule( server, "mod", *pkt ? "1" : "0", NO_FLAGS);
  5043.         if ( *pkt)  {
  5044.         int n;
  5045.         /* pull out the mod infomation */
  5046.         pkt++;
  5047.         add_rule( server, "mod_info_url", pkt, NO_FLAGS);
  5048.         pkt+= strlen( pkt)+1;
  5049.         if ( *pkt)
  5050.             add_rule( server, "mod_download_url", pkt, NO_FLAGS);
  5051.         pkt+= strlen( pkt)+1;
  5052.         if ( *pkt)
  5053.             add_rule( server, "mod_detail", pkt, NO_FLAGS);
  5054.         pkt+= strlen( pkt)+1;
  5055.         n= swap_long_from_little( pkt);
  5056.         sprintf( number, "%d", n);
  5057.         add_rule( server, "modversion", number, NO_FLAGS);
  5058.         pkt+= 4;
  5059.         n= swap_long_from_little( pkt);
  5060.         sprintf( number, "%d", n);
  5061.         add_rule( server, "modsize", number, NO_FLAGS);
  5062.         pkt+= 4;
  5063.         add_rule( server, "svonly", *pkt ? "1" : "0", NO_FLAGS);
  5064.         pkt++;
  5065.         add_rule( server, "cldll", *pkt ? "1" : "0", NO_FLAGS);
  5066.         pkt++;
  5067.         if ( pkt < end)
  5068.             add_rule( server, "secure", *pkt ? "1" : "0", NO_FLAGS);
  5069.         }
  5070.     }
  5071.  
  5072.     if ( get_player_info && server->num_players)  {
  5073.         server->next_player_info= server->num_players-1;
  5074.         send_player_request_packet( server);
  5075.     }
  5076.     if ( get_server_rules)  {
  5077.         server->next_rule= "";
  5078.         server->retry1= n_retries;
  5079.         send_rule_request_packet( server);
  5080.     }
  5081.     }
  5082.     /* 'players' response */
  5083.     else if ( rawpkt[4] == 'D' && server->players == NULL)  {
  5084.     unsigned int n= 0, temp;
  5085.     float *ingame= (float*) &temp;
  5086.     struct player *player;
  5087.     struct player **last_player= & server->players;
  5088.     if ( (unsigned int)rawpkt[5] > server->num_players)
  5089.         server->num_players= (unsigned int)rawpkt[5];
  5090.     pkt= &rawpkt[6];
  5091.     rawpkt[pktlen]= '\0';
  5092.     while (1)  {
  5093.         if ( *pkt != n+1)
  5094.         break;
  5095.         n++;
  5096.         pkt++;
  5097.         player= (struct player*) calloc( 1, sizeof(struct player));
  5098.         player->name= strdup( pkt);
  5099.         pkt+= strlen(pkt)+1;
  5100.         memcpy( &player->frags, pkt, 4);
  5101.         pkt+= 4;
  5102.         memcpy( &temp, pkt, 4);
  5103.         pkt+= 4;
  5104.         if ( big_endian)  {
  5105.         player->frags= swap_long( &player->frags);
  5106.         temp= swap_long( &temp);
  5107.         }
  5108.         player->connect_time= *ingame;
  5109.         *last_player= player;
  5110.         last_player= & player->next;
  5111.     }
  5112.     if ( n > server->num_players)
  5113.         server->num_players= n;
  5114.     server->next_player_info= server->num_players;
  5115.     }
  5116.     /* 'rules' response */
  5117.     else if ( rawpkt[4] == 'E' && server->next_rule != NULL)  {
  5118.     int n= 0;
  5119.     struct rule *rule;
  5120.     n= ((unsigned char*)rawpkt)[5] + ((unsigned char *)rawpkt)[6]*256;
  5121.     pkt= &rawpkt[7];
  5122.     while ( n)  {
  5123.         char *key= pkt;
  5124.         char *value;
  5125.         pkt+= strlen(pkt)+1;
  5126.         if ( pkt > end)
  5127.         break;
  5128.         value= pkt;
  5129.         pkt+= strlen(pkt)+1;
  5130.         if ( pkt > end)
  5131.         break;
  5132.         add_rule( server, key, value, NO_FLAGS);
  5133.         n--;
  5134.     }
  5135.     server->next_rule= NULL;
  5136.     }
  5137.     else if ( rawpkt[4] != 'E' && rawpkt[4] != 'D' && rawpkt[4] != 'm' &&
  5138.         rawpkt[4] != 'C' && show_errors)  {
  5139. /*    if ( pkt_count) { rawpkt-= 9; pktlen+= 9; } */
  5140.     fprintf( stderr, "Odd packet from HL server %s (packet len %d)\n",
  5141.         server->arg, pktlen);
  5142.     print_packet( server, rawpkt, pktlen);
  5143.     }
  5144.  
  5145.     cleanup_qserver( server, 0);
  5146. }
  5147.  
  5148.  
  5149. int
  5150. combine_packets( struct qserver *server)
  5151. {
  5152.     unsigned int ids[8];
  5153.     int maxes[8];
  5154.     int counts[8];
  5155.     int lengths[8];
  5156.     SavedData * segments[8][16];
  5157.     SavedData *sdata= & server->saved_data;
  5158.     int n_ids= 0, i, p;
  5159.  
  5160.     memset( &segments[0][0], 0, sizeof(segments));
  5161.     memset( &counts[0], 0, sizeof(counts));
  5162.     memset( &lengths[0], 0, sizeof(lengths));
  5163.  
  5164.     for ( ; sdata != NULL; sdata= sdata->next)  {
  5165.     if ( sdata->pkt_max == 0)
  5166.         continue;
  5167.     for (i= 0; i < n_ids; i++)
  5168.         if ( sdata->pkt_id == ids[i])
  5169.         break;
  5170.     if ( i >= n_ids)  {
  5171.         if ( n_ids >= 8)
  5172.         continue;
  5173.         ids[n_ids]= sdata->pkt_id;
  5174.         maxes[n_ids]= sdata->pkt_max;
  5175.         i= n_ids++;
  5176.     }
  5177.     else if ( maxes[i] != sdata->pkt_max)
  5178.         continue;
  5179.     if ( segments[i][sdata->pkt_index] == NULL)  {
  5180.         segments[i][sdata->pkt_index]= sdata;
  5181.         counts[i]++;
  5182.         lengths[i]+= sdata->datalen;
  5183.     }
  5184.     }
  5185.  
  5186.     for ( i= 0; i < n_ids; i++)  {
  5187.     char *combined;
  5188.     int datalen= 0;
  5189.     if ( counts[i] != maxes[i])
  5190.         continue;
  5191.  
  5192.     combined= (char*)malloc( lengths[i]);
  5193.     for ( p= 0; p < counts[i]; p++)  {
  5194.         if ( segments[i][p] == NULL)
  5195.         break;
  5196.         memcpy( combined + datalen, segments[i][p]->data,
  5197.         segments[i][p]->datalen);
  5198.         datalen+= segments[i][p]->datalen;
  5199.     }
  5200.     if ( p < counts[i])  {
  5201.         free( combined);
  5202.         continue;
  5203.     }
  5204.  
  5205.     for ( p= 0; p < counts[i]; p++)
  5206.         segments[i][p]->pkt_max= 0;
  5207.  
  5208.     server->type->packet_func( server, combined, datalen);
  5209.     free( combined);
  5210.     if ( server->saved_data.data == NULL)
  5211.         break;
  5212.     }
  5213.     return 0;
  5214. }
  5215.  
  5216. static int tribes_debug= 0;
  5217.  
  5218. void
  5219. deal_with_tribes_packet( struct qserver *server, char *rawpkt, int pktlen)
  5220. {
  5221.     unsigned char *pkt, *end;
  5222.     int len, pnum, ping, packet_loss, n_teams, t;
  5223.     struct player *player;
  5224.     struct player **teams= NULL;
  5225.     struct player **last_player= & server->players;
  5226.     char buf[24];
  5227.  
  5228.     if ( server->server_name == NULL)
  5229.     server->ping_total+= time_delta( &packet_recv_time,
  5230.         &server->packet_time1);
  5231.     else
  5232.     gettimeofday( &server->packet_time1, NULL);
  5233.  
  5234.     if ( pktlen < sizeof( tribes_info_reponse))  {
  5235.     cleanup_qserver( server, 1);
  5236.     return;
  5237.     }
  5238.     if ( get_player_info || get_server_rules)  {
  5239.     if ( strncmp( rawpkt, tribes_players_reponse,
  5240.             sizeof( tribes_players_reponse)) != 0)  {
  5241.         cleanup_qserver( server, 1);
  5242.         return;
  5243.     }
  5244.     }
  5245.     else if ( strncmp( rawpkt, tribes_info_reponse,
  5246.         sizeof( tribes_info_reponse)) != 0)  {
  5247.     cleanup_qserver( server, 1);
  5248.     return;
  5249.     }
  5250.  
  5251.     pkt= (unsigned char*) &rawpkt[sizeof( tribes_info_reponse)];
  5252.  
  5253.     len= *pkt;        /* game name: "Tribes" */
  5254.     add_nrule( server, "gamename", (char*)pkt+1, len);
  5255.     pkt+= len+1;
  5256.     len= *pkt;        /* version */
  5257.     add_nrule( server, "version", (char*)pkt+1, len);
  5258.     pkt+= len+1;
  5259.     len= *pkt;        /* server name */
  5260.     server->server_name= strndup( (char*)pkt+1, len);
  5261.     pkt+= len+1;
  5262.     add_rule( server, "dedicated", *pkt?"1":"0", NO_FLAGS);
  5263.     pkt++;        /* flag: dedicated server */
  5264.     add_rule( server, "needpass", *pkt?"1":"0", NO_FLAGS);
  5265.     pkt++;        /* flag: password on server */
  5266.     server->num_players= *pkt++;
  5267.     server->max_players= *pkt++;
  5268.  
  5269.     if ( !get_player_info && !get_server_rules)  {
  5270.     cleanup_qserver( server, 0);
  5271.     return;
  5272.     }
  5273.  
  5274.     sprintf( buf, "%u", (unsigned int)pkt[0] + (unsigned int)pkt[1]*256);
  5275.     add_rule( server, "cpu", buf, NO_FLAGS);
  5276.     pkt++;        /* cpu speed, lsb */
  5277.     pkt++;        /* cpu speed, msb */
  5278.  
  5279.     len= *pkt;        /* Mod (game) */
  5280.     add_nrule( server, "mods", (char*)pkt+1, len);
  5281.     pkt+= len+1;
  5282.  
  5283.     len= *pkt;        /* game (mission): "C&H" */
  5284.     add_nrule( server, "game", (char*)pkt+1, len);
  5285.     pkt+= len+1;
  5286.  
  5287.     len= *pkt;        /* Mission (map) */
  5288.     server->map_name= strndup( (char*)pkt+1, len);
  5289.     pkt+= len+1;
  5290.  
  5291.     len= *pkt;        /* description (contains Admin: and Email: ) */
  5292. if ( tribes_debug) printf( "%.*s\n", len, pkt+1);
  5293.     pkt+= len+1;
  5294.  
  5295.     n_teams= *pkt++;        /* number of teams */
  5296.     if ( n_teams == 255)  {
  5297.     cleanup_qserver( server, 1);
  5298.     return;
  5299.     }
  5300.     sprintf( buf, "%d", n_teams);
  5301.     add_rule( server, "numteams", buf, NO_FLAGS);
  5302.  
  5303.     len= *pkt;        /* first title */
  5304. if ( tribes_debug) printf( "%.*s\n", len, pkt+1);
  5305.     pkt+= len+1;
  5306.  
  5307.     len= *pkt;        /* second title */
  5308. if ( tribes_debug) printf( "%.*s\n", len, pkt+1);
  5309.     pkt+= len+1;
  5310.  
  5311.     if ( n_teams > 1)  {
  5312.     teams= (struct player**) calloc( 1, sizeof(struct player*) * n_teams);
  5313.     for ( t= 0; t < n_teams; t++)  {
  5314.         teams[t]= (struct player*) calloc(1, sizeof(struct player));
  5315.         teams[t]->number= TRIBES_TEAM;
  5316.         teams[t]->team= t;
  5317.         len= *pkt;        /* team name */
  5318.         teams[t]->name= strndup( (char*)pkt+1, len);
  5319. if ( tribes_debug) printf( "team#0 <%.*s>\n", len, pkt+1);
  5320.         pkt+= len+1;
  5321.  
  5322.         len= *pkt;        /* team score */
  5323. if ( len <= 2 && tribes_debug) printf( "%s score len %d\n", server->arg, len);
  5324.         if ( len > 2)  {
  5325.         strncpy( buf, (char*)pkt+1+3, len-3);
  5326.         buf[len-3]= '\0';
  5327.         }
  5328.         else
  5329.         buf[0]= '\0';
  5330.         teams[t]->frags= atoi( buf);
  5331. if ( tribes_debug) printf( "team#0 <%.*s>\n", len-3, pkt+1+3);
  5332.         pkt+= len+1;
  5333.     }
  5334.     }
  5335.     else  {
  5336.     len= *pkt;        /* DM team? */
  5337. if ( tribes_debug) printf( "%.*s\n", len, pkt+1);
  5338.     pkt+= len+1;
  5339.     pkt++;
  5340.     n_teams= 0;
  5341.     }
  5342.  
  5343.     pnum= 0;
  5344.     while ( (char*)pkt < (rawpkt+pktlen))  {
  5345.     ping= (unsigned int)*pkt << 2;
  5346.     pkt++;
  5347.     packet_loss= *pkt;
  5348.     pkt++;
  5349. if ( tribes_debug) printf( "player#%d, team #%d\n", pnum, (int)*pkt);
  5350.     pkt++;
  5351.     len= *pkt;
  5352.     if ( (char*)pkt+len > (rawpkt+pktlen))
  5353.         break;
  5354.     player= (struct player*) calloc( 1, sizeof(struct player));
  5355.     player->team= pkt[-1];
  5356.     if ( n_teams && player->team < n_teams)
  5357.         player->team_name= teams[player->team]->name;
  5358.     else if ( player->team == 255 && n_teams)
  5359.         player->team_name= "Unknown";
  5360.     player->ping= ping;
  5361.     player->packet_loss= packet_loss;
  5362.     player->name= strndup( (char*)pkt+1, len);
  5363. if ( tribes_debug)     printf( "player#%d, name %.*s\n", pnum, len, pkt+1);
  5364.     pkt+= len+1;
  5365.     len= *pkt;
  5366. if ( tribes_debug) printf( "player#%d, info <%.*s>\n", pnum, len, pkt+1);
  5367.     end= (unsigned char*) strchr( (char*)pkt+9, 0x9);
  5368.     if ( end)  {
  5369.         strncpy( buf, (char*)pkt+9, end-(pkt+9));
  5370.         buf[end-(pkt+9)]= '\0';
  5371.         player->frags= atoi( buf);
  5372. if ( tribes_debug) printf( "player#%d, score <%.*s>\n", pnum, end-(pkt+9), pkt+9);
  5373.     }
  5374.     *last_player= player;
  5375.     last_player= & player->next;
  5376.  
  5377.     pkt+= len+1;
  5378.     pnum++;
  5379.     }
  5380.  
  5381.     for ( t= n_teams; t;)  {
  5382.     t--;
  5383.     teams[t]->next= server->players;
  5384.     server->players= teams[t];
  5385.     }
  5386.     free( teams);
  5387.  
  5388.     cleanup_qserver( server, 0);
  5389. }
  5390.  
  5391. void
  5392. get_tribes2_player_type( struct player *player)
  5393. {
  5394.     char *name= player->name;
  5395.     for ( ; *name; name++)  {
  5396.     switch ( *name)  {
  5397.     case 0x8: player->type_flag= PLAYER_TYPE_NORMAL; continue;
  5398.     case 0xc: player->type_flag= PLAYER_TYPE_ALIAS; continue;
  5399.     case 0xe: player->type_flag= PLAYER_TYPE_BOT; continue;
  5400.     case 0xb: break;
  5401.     default: continue;
  5402.     }
  5403.     name++;
  5404.     if ( isprint( *name))  {
  5405.         char *n= name;
  5406.         for ( ; isprint(*n); n++)
  5407.         ;
  5408.         player->tribe_tag= strndup( name, n-name);
  5409.         name= n;
  5410.     }
  5411.     if ( !*name)
  5412.         break;
  5413.     }
  5414. }
  5415.  
  5416. void
  5417. deal_with_tribes2_packet( struct qserver *server, char *pkt, int pktlen)
  5418. {
  5419.     char str[256], *pktstart= pkt, *term, *start;
  5420.     unsigned int minimum_net_protocol, build_version, i, t, len, s, status;
  5421.     unsigned int net_protocol;
  5422.     unsigned short cpu_speed;
  5423.     int n_teams= 0, n_players;
  5424.     struct player **teams= NULL, *player;
  5425.     struct player **last_player= & server->players;
  5426.     int query_version;
  5427.  
  5428.     pkt[pktlen]= '\0';
  5429.  
  5430.     if ( server->server_name == NULL)
  5431.     server->ping_total+= time_delta( &packet_recv_time,
  5432.         &server->packet_time1);
  5433. /*
  5434.     else
  5435.     gettimeofday( &server->packet_time1, NULL);
  5436. */
  5437.  
  5438.     if ( pkt[0] == TRIBES2_RESPONSE_PING)  {
  5439.     if ( pkt[6] < 4 || pkt[6] > 12 || strncmp( pkt+7, "VER", 3) != 0)  {
  5440.         cleanup_qserver( server, 1);
  5441.         return;
  5442.     }
  5443.     strncpy( str, pkt+10, pkt[6]-3);
  5444.     str[ pkt[6]-3]= '\0';
  5445.     query_version= atoi( str);
  5446.     add_nrule(server,"queryversion", pkt+7, pkt[6]);
  5447.     pkt+= 7 + pkt[6];
  5448.  
  5449.     server->protocol_version= query_version;
  5450.     if ( query_version != 3 && query_version != 5) {
  5451.         server->server_name= strdup( "Unknown query version");
  5452.         cleanup_qserver( server, 1);
  5453.         return;
  5454.     }
  5455.  
  5456.     if ( query_version == 5)  {
  5457.         net_protocol= swap_long_from_little( pkt);
  5458.         sprintf( str, "%u", net_protocol);
  5459.         add_rule(server,"net_protocol",str, NO_FLAGS);
  5460.         pkt+= 4;
  5461.     }
  5462.     minimum_net_protocol= swap_long_from_little( pkt);
  5463.     sprintf( str, "%u", minimum_net_protocol);
  5464.     add_rule(server,"minimum_net_protocol",str, NO_FLAGS);
  5465.     pkt+= 4;
  5466.     build_version= swap_long_from_little( pkt);
  5467.     sprintf( str, "%u", build_version);
  5468.     add_rule(server,"build_version",str, NO_FLAGS);
  5469.     pkt+= 4;
  5470.  
  5471.     server->server_name= strndup( pkt+1, *(unsigned char*)(pkt));
  5472.  
  5473.     send( server->fd, server->type->player_packet,
  5474.         server->type->status_len, 0);
  5475.     return;
  5476.     }
  5477.     else if ( pkt[0] != TRIBES2_RESPONSE_INFO)  {
  5478.     cleanup_qserver( server, 1);
  5479.     return;
  5480.     }
  5481.  
  5482.     pkt+= 6;
  5483.     for ( i= 0; i < *(unsigned char *)pkt; i++)
  5484.     if ( !isprint(pkt[i+1]))  {
  5485.         cleanup_qserver( server, 1);
  5486.         return;
  5487.     }
  5488.     add_nrule( server, server->type->game_rule, pkt+1, *(unsigned char *)pkt);
  5489.     server->game= strndup( pkt+1, *(unsigned char *)pkt);
  5490.     pkt+= *pkt + 1;
  5491.     add_nrule( server, "mission", pkt+1, *(unsigned char *)pkt);
  5492.     pkt+= *pkt + 1;
  5493.     server->map_name= strndup( pkt+1, *(unsigned char *)pkt);
  5494.     pkt+= *pkt + 1;
  5495.  
  5496.     status= *(unsigned char *)pkt;
  5497.     sprintf( str, "%u", status);
  5498.     add_rule( server, "status", str, NO_FLAGS);
  5499.     if ( status & TRIBES2_STATUS_DEDICATED)
  5500.     add_rule( server, "dedicated", "1", NO_FLAGS);
  5501.     if ( status & TRIBES2_STATUS_PASSWORD)
  5502.     add_rule( server, "password", "1", NO_FLAGS);
  5503.     if ( status & TRIBES2_STATUS_LINUX)
  5504.     add_rule( server, "linux", "1", NO_FLAGS);
  5505.     if ( status & TRIBES2_STATUS_TEAMDAMAGE)
  5506.     add_rule( server, "teamdamage", "1", NO_FLAGS);
  5507.     if ( server->protocol_version == 3)  {
  5508.     if ( status & TRIBES2_STATUS_TOURNAMENT_VER3)
  5509.         add_rule( server, "tournament", "1", NO_FLAGS);
  5510.     if ( status & TRIBES2_STATUS_NOALIAS_VER3)
  5511.         add_rule( server, "no_aliases", "1", NO_FLAGS);
  5512.     }
  5513.     else  {
  5514.     if ( status & TRIBES2_STATUS_TOURNAMENT)
  5515.         add_rule( server, "tournament", "1", NO_FLAGS);
  5516.     if ( status & TRIBES2_STATUS_NOALIAS)
  5517.         add_rule( server, "no_aliases", "1", NO_FLAGS);
  5518.     }
  5519.     pkt++;
  5520.     server->num_players= *(unsigned char *)pkt;
  5521.     pkt++;
  5522.     server->max_players= *(unsigned char *)pkt;
  5523.     pkt++;
  5524.     sprintf( str, "%u", *(unsigned char *)pkt);
  5525.     add_rule( server, "bot_count", str, NO_FLAGS);
  5526.     pkt++;
  5527.     cpu_speed= swap_short_from_little( pkt);
  5528.     sprintf( str, "%hu", cpu_speed);
  5529.     add_rule( server, "cpu_speed", str, NO_FLAGS);
  5530.     pkt+= 2;
  5531.  
  5532.     if ( strcmp( server->server_name, "VER3") == 0)  {
  5533.     free( server->server_name);
  5534.     server->server_name= strndup( pkt+1, *(unsigned char*)pkt);
  5535.     }
  5536.     else
  5537.     add_nrule( server, "info", pkt+1, *(unsigned char*)pkt);
  5538.  
  5539.     pkt+= *(unsigned char*)pkt + 1;
  5540.     len= swap_short_from_little( pkt);
  5541.     pkt+= 2;
  5542.     start= pkt;
  5543.     if ( len+(pkt-pktstart) > pktlen)
  5544.     len-= (len+(pkt-pktstart)) - pktlen;
  5545.  
  5546.     if ( len == 0 || pkt-pktstart >= pktlen) goto info_done;
  5547.  
  5548.     term= strchr( pkt, 0xa);
  5549.     if ( !term) goto info_done;
  5550.     *term= '\0';
  5551.     n_teams= atoi( pkt);
  5552.     sprintf( str, "%d", n_teams);
  5553.     add_rule( server, "numteams", str, NO_FLAGS);
  5554.     pkt= term + 1;
  5555.  
  5556.     if ( pkt-pktstart >= pktlen) goto info_done;
  5557.  
  5558.     teams= (struct player**) calloc( 1, sizeof(struct player*) * n_teams);
  5559.     for ( t= 0; t < n_teams; t++)  {
  5560.     teams[t]= (struct player*) calloc(1, sizeof(struct player));
  5561.     teams[t]->number= TRIBES_TEAM;
  5562.     teams[t]->team= t;
  5563.     /* team name */
  5564.     term= strchr( pkt, 0x9);
  5565.     if ( !term) { n_teams= t; goto info_done; }
  5566.     teams[t]->name= strndup( pkt, term-pkt);
  5567.     pkt= term+1;
  5568.     term= strchr( pkt, 0xa);
  5569.     if ( !term) { n_teams= t; goto info_done; }
  5570.     *term='\0';
  5571.     teams[t]->frags= atoi(pkt);
  5572.     pkt= term+1;
  5573.     if ( pkt-pktstart >= pktlen) goto info_done;
  5574.     }
  5575.  
  5576.     term= strchr( pkt, 0xa);
  5577.     if ( !term || term-start >= len) goto info_done;
  5578.     *term= '\0';
  5579.     n_players= atoi( pkt);
  5580.     pkt= term + 1;
  5581.  
  5582.     for ( i= 0; i < n_players && pkt-start < len; i++)  {
  5583.     pkt++;        /* skip first byte (0x10) */
  5584.     if ( pkt-start >= len) break;
  5585.     player= (struct player*) calloc( 1, sizeof(struct player));
  5586.     term= strchr( pkt, 0x11);
  5587.     if ( !term || term-start >= len) {
  5588.         free( player);
  5589.         break;
  5590.     }
  5591.     player->name= strndup( pkt, term-pkt);
  5592.     get_tribes2_player_type( player);
  5593.     pkt= term+1;
  5594.     pkt++;        /* skip 0x9 */
  5595.     if ( pkt-start >= len) break;
  5596.     term= strchr( pkt, 0x9);
  5597.     if ( !term || term-start >= len) {
  5598.         free( player->name);
  5599.         free( player);
  5600.         break;
  5601.     }
  5602.     for ( t= 0; t < n_teams; t++)  {
  5603.         if ( term-pkt == strlen(teams[t]->name) &&
  5604.             strncmp( pkt, teams[t]->name, term-pkt) == 0)
  5605.         break;
  5606.     }
  5607.     if ( t == n_teams)  {
  5608.         player->team= -1;
  5609.         player->team_name= "Unassigned";
  5610.     }
  5611.     else  {
  5612.         player->team= t;
  5613.         player->team_name= teams[t]->name;
  5614.     }
  5615.     pkt= term+1;
  5616.     for ( s= 0; *pkt != 0xa && pkt-start < len; pkt++)
  5617.         str[s++]= *pkt;
  5618.     str[s]= '\0';
  5619.     player->frags= atoi(str);
  5620.     if ( *pkt == 0xa)
  5621.         pkt++;
  5622.  
  5623.     *last_player= player;
  5624.     last_player= & player->next;
  5625.     }
  5626.  
  5627. info_done:
  5628.     for ( t= n_teams; t;)  {
  5629.     t--;
  5630.     teams[t]->next= server->players;
  5631.     server->players= teams[t];
  5632.     }
  5633.     if ( teams) free( teams);
  5634.  
  5635.     cleanup_qserver( server, 1);
  5636.     return;
  5637. }
  5638.  
  5639. /* postions of map name, player name (in player substring), zero-based */
  5640. #define BFRIS_MAP_POS 18
  5641. #define BFRIS_PNAME_POS 11
  5642. void
  5643. deal_with_bfris_packet( struct qserver *server, char *rawpkt, int pktlen)
  5644. {
  5645.   int i, player_data_pos, nplayers;
  5646.   SavedData *sdata;
  5647.   unsigned char *saved_data;
  5648.   int saved_data_size;
  5649.  
  5650.   server->ping_total += time_delta( &packet_recv_time,
  5651.                     &server->packet_time1);
  5652.  
  5653.   /* add to the data previously saved */
  5654.   sdata= & server->saved_data;
  5655.   if (! sdata->data)
  5656.     sdata->data = (char*)malloc(pktlen);
  5657.   else
  5658.     sdata->data = (char*)realloc(sdata->data,sdata->datalen + pktlen);
  5659.  
  5660.   memcpy(sdata->data + sdata->datalen, rawpkt, pktlen);
  5661.   sdata->datalen += pktlen;
  5662.  
  5663.   saved_data= (unsigned char*) sdata->data;
  5664.   saved_data_size= sdata->datalen;
  5665.  
  5666.   /* after we get the server portion of the data, server->game != NULL */
  5667.   if (!server->game) {
  5668.  
  5669.     /* server data goes up to map name */
  5670.     if (sdata->datalen <= BFRIS_MAP_POS)
  5671.       return;
  5672.  
  5673.     /* see if map name is complete */
  5674.     player_data_pos=0;
  5675.     for (i=BFRIS_MAP_POS; i<saved_data_size; i++) {
  5676.       if (saved_data[i] == '\0') {
  5677.     player_data_pos = i+1;
  5678.     /* data must extend beyond map name */
  5679.     if (saved_data_size <= player_data_pos)
  5680.       return;
  5681.     break;
  5682.       }
  5683.     }
  5684.  
  5685.     /* did we find beginning of player data? */
  5686.     if (!player_data_pos)
  5687.       return;
  5688.  
  5689.     /* now we can go ahead and fill in server data */
  5690.     server->map_name = strdup((char*)saved_data + BFRIS_MAP_POS);
  5691.     server->max_players = saved_data[12];
  5692.     server->protocol_version = saved_data[11];
  5693.  
  5694.     /* save game type */
  5695.     switch (saved_data[13] & 15) {
  5696.     case 0: server->game = "FFA"; break;
  5697.     case 5: server->game = "Rover"; break;
  5698.     case 6: server->game = "Occupation"; break;
  5699.     case 7: server->game = "SPAAL"; break;
  5700.     case 8: server->game = "CTF"; break;
  5701.     default:
  5702.       server->game = "unknown"; break;
  5703.     }
  5704.     add_rule(server,server->type->game_rule,server->game, NO_FLAGS);
  5705.  
  5706.     if (get_server_rules) {
  5707.       char buf[24];
  5708.  
  5709.       /* server revision */
  5710.       sprintf(buf,"%d",(unsigned int)saved_data[11]);
  5711.       add_rule(server,"Revision",buf, NO_FLAGS);
  5712.  
  5713.       /* latency */
  5714.       sprintf(buf,"%d",(unsigned int)saved_data[10]);
  5715.       add_rule(server,"Latency",buf, NO_FLAGS);
  5716.  
  5717.       /* player allocation */
  5718.       add_rule(server,"Allocation",saved_data[13] & 16 ? "Automatic" : "Manual", NO_FLAGS);
  5719.  
  5720.     }
  5721.  
  5722.   }
  5723.  
  5724.   /* If we got this far, we know the data saved goes at least to the start of
  5725.      the player information, and that the server data is taken care of.
  5726.   */
  5727.  
  5728.   /* start of player data */
  5729.   player_data_pos = BFRIS_MAP_POS + strlen((char*)saved_data+BFRIS_MAP_POS) + 1;
  5730.  
  5731.   /* ensure all player data have arrived */
  5732.   nplayers = 0;
  5733.   while (saved_data[player_data_pos] != '\0') {
  5734.  
  5735.     player_data_pos += BFRIS_PNAME_POS;
  5736.  
  5737.     /* does player data extend to player name? */
  5738.     if (saved_data_size <= player_data_pos + 1)
  5739.       return;
  5740.  
  5741.     /* does player data extend to end of player name? */
  5742.     for (i=0; player_data_pos + i < saved_data_size; i++) {
  5743.  
  5744.       if (saved_data_size == player_data_pos + i + 1)
  5745.     return;
  5746.  
  5747.       if (saved_data[player_data_pos + i] == '\0') {
  5748.     player_data_pos += i + 1;
  5749.     nplayers++;
  5750.     break;
  5751.       }
  5752.     }
  5753.   }
  5754.   /* all player data are complete */
  5755.  
  5756.   server->num_players = nplayers;
  5757.  
  5758.   if (get_player_info) {
  5759.  
  5760.     /* start of player data */
  5761.     player_data_pos = BFRIS_MAP_POS + strlen((char*)saved_data+BFRIS_MAP_POS) + 1;
  5762.  
  5763.     for (i=0; i<nplayers; i++) {
  5764.       struct player *player;
  5765.       player= add_player( server, saved_data[player_data_pos]);
  5766.  
  5767.       player->ship = saved_data[player_data_pos + 1]; 
  5768.       player->ping = saved_data[player_data_pos + 2];
  5769.       player->frags = saved_data[player_data_pos + 3];
  5770.       player->team = saved_data[player_data_pos + 4];
  5771.       switch (player->team) {
  5772.       case 0: player->team_name = "silver"; break;
  5773.       case 1: player->team_name = "red"; break;
  5774.       case 2: player->team_name = "blue"; break;
  5775.       case 3: player->team_name = "green"; break;
  5776.       case 4: player->team_name = "purple"; break;
  5777.       case 5: player->team_name = "yellow"; break;
  5778.       case 6: player->team_name = "cyan"; break;
  5779.       default:
  5780.     player->team_name = "unknown"; break;
  5781.       }
  5782.       player->room = saved_data[player_data_pos + 5];
  5783.  
  5784.       /* score is little-endian integer */
  5785.       player->score =
  5786.     saved_data[player_data_pos+7] +
  5787.     (saved_data[player_data_pos+8] << 8) +
  5788.     (saved_data[player_data_pos+9] << 16) +
  5789.     (saved_data[player_data_pos+10] << 24);
  5790.  
  5791.       /* for archs with > 4-byte int */
  5792.       if (player->score & 0x80000000)
  5793.     player->score = -(~(player->score)) - 1;
  5794.  
  5795.  
  5796.       player_data_pos += BFRIS_PNAME_POS;
  5797.       player->name = strdup((char*)saved_data + player_data_pos);
  5798.  
  5799.       player_data_pos += strlen(player->name) + 1;
  5800.     }
  5801.  
  5802.   }
  5803.  
  5804.   server->server_name = "BFRIS Server";
  5805.   cleanup_qserver(server, 1);
  5806.   return;
  5807. }
  5808.  
  5809. struct rule *
  5810. add_uchar_rule( struct qserver *server, char *key, unsigned char value) 
  5811. {
  5812.     char buf[24];
  5813.     sprintf( buf, "%u", (unsigned)value);
  5814.     return add_rule( server, key, buf, NO_FLAGS);
  5815. }
  5816.  
  5817. void
  5818. deal_with_descent3_packet( struct qserver *server, char *rawpkt, int pktlen)
  5819. {
  5820.     char *pkt;
  5821.     char buf[24];
  5822.   
  5823.     if ( server->server_name == NULL)
  5824.     server->ping_total += time_delta( &packet_recv_time,
  5825.                     &server->packet_time1);
  5826.  
  5827.     if ( pktlen < 4)  {
  5828.     fprintf( stderr, "short d3 packet\n");
  5829.     print_packet( server, rawpkt, pktlen);
  5830.     cleanup_qserver( server, 1);
  5831.     return;
  5832.     }
  5833.  
  5834.     /* 'info' response */
  5835.     if ( rawpkt[1] == 0x1f)  {
  5836.     if ( server->server_name != NULL)
  5837.     {
  5838.         cleanup_qserver( server, 1);
  5839.         return;
  5840.     }
  5841.         
  5842.     
  5843.     pkt= &rawpkt[0x15];
  5844.     server->server_name= strdup( pkt);
  5845.     pkt+= strlen(pkt)+2;
  5846.     server->map_name= strdup( pkt); /* mission name (blah.mn3) */
  5847.     pkt+= strlen(pkt)+2;
  5848.     add_rule( server, "level_name", pkt, NO_FLAGS);
  5849.     pkt+= strlen(pkt)+2;
  5850.     add_rule( server, "gametype", pkt, NO_FLAGS);
  5851.     pkt+= strlen(pkt)+1;
  5852.  
  5853.     sprintf( buf, "%hu", swap_short_from_little(pkt));
  5854.     add_rule( server, "level_num", buf, NO_FLAGS);
  5855.     pkt+=2;
  5856.     server->num_players= swap_short_from_little(pkt);
  5857.     pkt+=2;
  5858.     server->max_players= swap_short_from_little(pkt);
  5859.     pkt+=2;
  5860.  
  5861.     /* unknown/undecoded fields.. stuff like permissible, banned items/ships, etc */
  5862.     add_uchar_rule( server, "u0", pkt[0]);
  5863.     add_uchar_rule( server, "u1", pkt[1]);
  5864.     add_uchar_rule( server, "u2", pkt[2]);
  5865.     add_uchar_rule( server, "u3", pkt[3]);
  5866.     add_uchar_rule( server, "u4", pkt[4]);
  5867.     add_uchar_rule( server, "u5", pkt[5]);
  5868.     add_uchar_rule( server, "u6", pkt[6]);
  5869.     add_uchar_rule( server, "u7", pkt[7]);
  5870.     add_uchar_rule( server, "u8", pkt[8]);
  5871.  
  5872.     add_uchar_rule( server, "randpowerup", !(pkt[4]&1)); /* randomize powerup spawn */
  5873.     add_uchar_rule( server, "acccollisions", (pkt[5]&4) > 0); /* accurate collision detection */
  5874.     add_uchar_rule( server, "brightships", (pkt[5]&16) > 0); /* bright player ships */
  5875.     add_uchar_rule( server, "mouselook", (pkt[6]&1) > 0); /* mouselook enabled */
  5876.     sprintf( buf, "%s%s", (pkt[4]&16)?"PP":"CS", (pkt[6]&1)?"-ML":"");
  5877.     add_rule( server, "servertype", buf, NO_FLAGS);
  5878.  
  5879.     sprintf( buf, "%hhu", pkt[9]);
  5880.     add_rule( server, "difficulty", buf, NO_FLAGS);
  5881.     
  5882.     /* unknown/undecoded fields after known flags removed */
  5883.     add_uchar_rule( server, "x4", pkt[4] & ~(1+16));
  5884.     add_uchar_rule( server, "x5", pkt[5] & ~(4+16));
  5885.     add_uchar_rule( server, "x6", pkt[6] & ~1);
  5886.     
  5887.     if ( get_player_info && server->num_players)  {
  5888.         server->next_player_info= 0;
  5889.         send_player_request_packet( server);
  5890.         cleanup_qserver( server, 0);
  5891.         return;
  5892.     }
  5893.     
  5894.     }
  5895.     /* MP_PLAYERLIST_DATA */
  5896.     else if ( rawpkt[1] == 0x73)  {
  5897.     struct player *player;
  5898.     struct player **last_player= & server->players;
  5899.     
  5900.     if ( server->players != NULL)
  5901.     {
  5902.         cleanup_qserver( server, 1);
  5903.         return;
  5904.     }
  5905.  
  5906.     pkt= &rawpkt[0x4];
  5907.     while (*pkt)  {
  5908.         player= (struct player*) calloc( 1, sizeof(struct player));
  5909.         player->name= strdup( pkt);
  5910.         pkt+= strlen(pkt) + 1;
  5911.         *last_player= player;
  5912.         last_player= & player->next;
  5913.     }
  5914.     server->next_player_info= NO_PLAYER_INFO;
  5915.     }
  5916.     else {
  5917.     fprintf( stderr, "unknown d3 packet\n");
  5918.     print_packet( server, rawpkt, pktlen);
  5919.     }
  5920.     cleanup_qserver( server, 1);
  5921.     return;
  5922. }
  5923.  
  5924.  
  5925. void
  5926. deal_with_gamespy_master_response( struct qserver *server, char *rawpkt, int pktlen)
  5927. {
  5928.     if ( pktlen == 0)  {
  5929.     int len= server->saved_data.datalen;
  5930.     char *data= server->saved_data.data;
  5931.     char *ip, *portstr;
  5932.     unsigned int ipaddr;
  5933.     unsigned short port;
  5934.     int master_pkt_max;
  5935.  
  5936.     server->server_name= "Gamespy Master";
  5937.  
  5938.     master_pkt_max= (len / 20) * 6;
  5939.     server->master_pkt= (char*) malloc( master_pkt_max);
  5940.     server->master_pkt_len= 0;
  5941.  
  5942.     while ( len)  {
  5943.         for ( ; len && *data == '\\'; data++, len--) ;
  5944.         if ( len < 3) break;
  5945.         if ( data[0] == 'i' && data[1] == 'p' && data[2] == '\\')  {
  5946.         data+= 3;
  5947.         len-= 3;
  5948.         ip= data;
  5949.         portstr= NULL;
  5950.         for ( ; len && *data != '\\'; data++, len--)  {
  5951.             if ( *data == ':')  {
  5952.             portstr= data+1;
  5953.             *data= '\0';
  5954.             }
  5955.         }
  5956.         if ( len == 0)
  5957.             break;
  5958.         *data++= '\0';
  5959.         len--;
  5960.         ipaddr= inet_addr( ip);
  5961.         if ( portstr)
  5962.             port= htons( (unsigned short)atoi( portstr));
  5963.         else
  5964.             port= htons( 28000);   /* ## default port */
  5965.         if ( server->master_pkt_len >= master_pkt_max)  {
  5966.             master_pkt_max+= 20*6;
  5967.             server->master_pkt= (char*) realloc( server->master_pkt,
  5968.             master_pkt_max);
  5969.         }
  5970.         memcpy( server->master_pkt + server->master_pkt_len,
  5971.             &ipaddr, 4);
  5972.         memcpy( server->master_pkt + server->master_pkt_len + 4,
  5973.             &port, 2);
  5974.         server->master_pkt_len+= 6;
  5975.         }
  5976.         else
  5977.         for ( ; len && *data != '\\'; data++, len--) ;
  5978.     }
  5979.  
  5980.     server->n_servers= server->master_pkt_len / 6;
  5981.     server->next_player_info= -1;
  5982.     server->retry1= 0;
  5983.  
  5984.     cleanup_qserver( server, 1);
  5985.     return;
  5986.     }
  5987.  
  5988.     if (! server->saved_data.data)
  5989.     server->saved_data.data= (char*)malloc( pktlen);
  5990.     else
  5991.     server->saved_data.data= (char*)realloc( server->saved_data.data,
  5992.         server->saved_data.datalen + pktlen);
  5993.  
  5994.     memcpy( server->saved_data.data + server->saved_data.datalen, rawpkt, pktlen);
  5995.     server->saved_data.datalen+= pktlen;
  5996.  
  5997. }
  5998.  
  5999. /* Misc utility functions
  6000.  */
  6001.  
  6002. char *
  6003. strndup( char *string, int len)
  6004. {
  6005.     char *result;
  6006.     result= (char*) malloc( len+1);
  6007.     memcpy( result, string, len);
  6008.     result[len]= '\0';
  6009.     return result;
  6010. }
  6011.  
  6012. unsigned int
  6013. swap_long( void *l)
  6014. {
  6015.     unsigned char *b= (unsigned char *) l;
  6016.     return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
  6017. }
  6018.  
  6019. unsigned short
  6020. swap_short( void *l)
  6021. {
  6022.     unsigned char *b= (unsigned char *) l;
  6023.     return (unsigned short)b[0] | (b[1]<<8);
  6024. }
  6025.  
  6026. unsigned int
  6027. swap_long_from_little( void *l)
  6028. {
  6029.     unsigned char *b= (unsigned char *) l;
  6030.     unsigned int result;
  6031.     if ( little_endian)
  6032.     memcpy( &result, l, 4);
  6033.     else
  6034.     result= (unsigned int)b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
  6035.     return result;
  6036. }
  6037.  
  6038. unsigned short
  6039. swap_short_from_little( void *l)
  6040. {
  6041.     unsigned char *b= (unsigned char *) l;
  6042.     unsigned short result;
  6043.     if ( little_endian)
  6044.     memcpy( &result, l, 2);
  6045.     else
  6046.     result= (unsigned short)b[0] | ((unsigned short)b[1]<<8);
  6047.     return result;
  6048. }
  6049.  
  6050. #define MAXSTRLEN 2048
  6051.  
  6052. char *
  6053. xml_escape( char *string)
  6054. {
  6055.     static char _buf[4][MAXSTRLEN];
  6056.     static int _buf_index= 0, c;
  6057.     char *result, *b;
  6058.     
  6059.     if ( string == NULL)
  6060.     return "";
  6061.  
  6062.     if ( xml_encoding == ENCODING_LATIN_1 && strpbrk( string, "&<>") == NULL)
  6063.     return string;
  6064.  
  6065.     result= &_buf[_buf_index][0];
  6066.     _buf_index= (_buf_index+1) % 4;
  6067.  
  6068.     b= result;
  6069.     for ( ; *string; string++)  {
  6070.     c= *string;
  6071.     switch ( c)  {
  6072.     case '&':
  6073.         *b++= '&';
  6074.         *b++= 'a';
  6075.         *b++= 'm';
  6076.         *b++= 'p';
  6077.         *b++= ';';
  6078.         continue;
  6079.     case '<':
  6080.         *b++= '&';
  6081.         *b++= 'l';
  6082.         *b++= 't';
  6083.         *b++= ';';
  6084.         continue;
  6085.     case '>':
  6086.         *b++= '&';
  6087.         *b++= 'g';
  6088.         *b++= 't';
  6089.         *b++= ';';
  6090.         continue;
  6091.     default:
  6092.         break;
  6093.     }
  6094.     if ( xml_encoding == ENCODING_LATIN_1)  {
  6095.         if ( isprint(c))
  6096.         *b++= c;
  6097.         else
  6098.         b+= sprintf( b, "&#%u;", c);
  6099.     }
  6100.     else if ( xml_encoding == ENCODING_UTF_8)  {
  6101.         if ( (c & 0x80) == 0)
  6102.         *b++= c;
  6103.         else  {
  6104.         *b++= 0xC0 | (0x03 & (c >> 6)) ;
  6105.         *b++= 0x80 | (0x3F & c) ;
  6106.         }
  6107.     }
  6108.     }
  6109.     *b= '\0';
  6110.     return result;
  6111. }
  6112.  
  6113.  
  6114. static char *quake3_escape_colors[8] = {
  6115. "black", "red", "green", "yellow", "blue", "cyan", "magenta", "white"
  6116. };
  6117.  
  6118. static char *sof_colors[32] = {
  6119. "FFFFFF","FFFFFF","FF0000","00FF00","FFFF00","0000FF","FF00FF","00FFFF",
  6120. "000000","7F7F7F","702D07","7F0000","007F00","FFFFFF","007F7F","00007F",
  6121. "564D28","4C5E36","370B65","005572","54647E","1E2A63","66097B","705E61",
  6122. "980053","960018","702D07","54492A","61A997","CB8F39","CF8316","FF8020"
  6123. };
  6124.  
  6125.  
  6126. char *
  6127. xform_name( char *string, struct qserver *server)
  6128. {
  6129.     static char _buf1[1024], _buf2[1024];
  6130.     static char *_q= &_buf1[0];
  6131.     unsigned char *s= (unsigned char*) string;
  6132.     char *q;
  6133.     int is_server_name= (string == server->server_name);
  6134.     int font_tag= 0;
  6135.  
  6136.     _q= _q == _buf1 ? _buf2 : _buf1;
  6137.     q= _q;
  6138.  
  6139.     if ( s == NULL)  {
  6140.     q[0]= '?';
  6141.     q[1]= '\0';
  6142.     return _q;
  6143.     }
  6144.  
  6145.     if ( hex_player_names && !is_server_name)  {
  6146.     for ( ; *s; s++, q+= 2)
  6147.         sprintf( q, "%02x", *s);
  6148.     *q= '\0';
  6149.     return _q;
  6150.     }
  6151.  
  6152.     if ( server->type->flags & TF_QUAKE3_NAMES)  {
  6153.     for ( ; *s; s++)  {
  6154.         if ( *s == '^' && *(s+1) != '^')  {
  6155.         if ( *(s+1) == '\0') break;
  6156.         if ( html_names == 1) {
  6157.             q+= sprintf( q, "%s<font color=\"%s\">",
  6158.             font_tag?"</font>":"",
  6159.             quake3_escape_colors[ *(s+1) & 0x7]);
  6160.             s++;
  6161.             font_tag= 1;
  6162.         }
  6163.         else if ( strip_carets)
  6164.             s++;
  6165.         else
  6166.             *q++= *s;
  6167.         }
  6168.         else if ( html_mode && *s == '<')  {
  6169.         strcpy( q, "<");
  6170.         q+= 4;
  6171.         }
  6172.         else if ( html_mode && *s == '>')  {
  6173.         strcpy( q, ">");
  6174.         q+= 4;
  6175.         }
  6176.         else if ( html_mode && *s == '&')  {
  6177.         strcpy( q, "&");
  6178.         q+= 5;
  6179.         }
  6180.         else if ( isprint(*s))
  6181.         *q++= *s;
  6182.         else if ( *s == '\033')
  6183.         ;
  6184.         else if ( *s == 0x80)
  6185.         *q++= '(';
  6186.         else if ( *s == 0x81)
  6187.         *q++= '=';
  6188.         else if ( *s == 0x82)
  6189.         *q++= ')';
  6190.         else if ( *s == 0x10 || *s == 0x90)
  6191.         *q++= '[';
  6192.         else if ( *s == 0x11 || *s == 0x91)
  6193.         *q++= ']';
  6194.         else if ( *s >= 0x92 && *s <= 0x9a) 
  6195.         *q++= *s - 98;
  6196.         else if ( *s >= 0xa0 && *s <= 0xe0)
  6197.         *q++= *s - 128;
  6198.         else if ( *s >= 0xe1 && *s <= 0xfa)
  6199.         *q++= *s - 160;
  6200.         else if ( *s >= 0xfb && *s <= 0xfe)
  6201.         *q++= *s - 128;
  6202.     }
  6203.         *q= '\0';
  6204.     }
  6205.     else if ( !is_server_name && (server->type->flags & TF_TRIBES2_NAMES))  {
  6206.     for ( ; *s; s++)  {
  6207.         if ( html_mode && *s == '<')  {
  6208.         strcpy( q, "<");
  6209.         q+= 4;
  6210.         continue;
  6211.         }
  6212.         else if ( html_mode && *s == '>')  {
  6213.         strcpy( q, ">");
  6214.         q+= 4;
  6215.         continue;
  6216.         }
  6217.         else if ( html_mode && *s == '&')  {
  6218.         strcpy( q, "&");
  6219.         q+= 5;
  6220.         continue;
  6221.         }
  6222.         else if ( isprint(*s))  {
  6223.         *q++= *s;
  6224.         continue;
  6225.         }
  6226.         if ( html_names == 1 && s[1] != '\0')  {
  6227.         char *font_color;
  6228.         switch( *s)  {
  6229.         case 0x8: font_color= "white"; break;    /* normal */
  6230.         case 0xb: font_color= "yellow"; break;    /* tribe tag */
  6231.         case 0xc: font_color= "blue"; break;    /* alias */
  6232.         case 0xe: font_color= "green"; break;    /* bot */
  6233.         default: font_color= NULL;
  6234.         }
  6235.         if ( font_color)  {
  6236.             q+= sprintf( q, "%s<font color=\"%s\">",
  6237.             font_tag?"</font>":"",
  6238.             font_color);
  6239.             font_tag= 1;
  6240.         }
  6241.         }
  6242.     }
  6243.     *q= '\0';
  6244.     }
  6245.     else if ( !is_server_name || (server->type->flags & TF_SOF_NAMES))  {
  6246.     for ( ; *s; s++)  {
  6247.         if ( html_mode && *s == '<')  {
  6248.         strcpy( q, "<");
  6249.         q+= 4;
  6250.         continue;
  6251.         }
  6252.         else if ( html_mode && *s == '>')  {
  6253.         strcpy( q, ">");
  6254.         q+= 4;
  6255.         continue;
  6256.         }
  6257.         else if ( html_mode && *s == '&')  {
  6258.         strcpy( q, "&");
  6259.         q+= 5;
  6260.         continue;
  6261.         }
  6262.  
  6263.         if ( *s < ' ' )  {
  6264.             if ( html_names == 1) {
  6265.                 q+= sprintf( q, "%s<font color=\"#%s\">",
  6266.                 font_tag?"</font>":"",
  6267.                 sof_colors[ *(s) ]);
  6268.                 font_tag= 1;
  6269.             }
  6270.         }
  6271.         else if ( isprint(*s))
  6272.         *q++= *s;
  6273. /* ## more fixes below; double check against real sof servers */
  6274.         else if ( *s >= 0xa0)
  6275.         *q++= *s & 0x7f;
  6276.         else if ( *s >= 0x92 && *s < 0x9c)
  6277.         *q++= '0' + (*s - 0x92);
  6278.         else if ( *s >= 0x12 && *s < 0x1c)
  6279.         *q++= '0' + (*s - 0x12);
  6280.         else if ( *s == 0x90 || *s == 0x10)
  6281.         *q++= '[';
  6282.         else if ( *s == 0x91 || *s == 0x11)
  6283.         *q++= ']';
  6284.         else if ( *s == 0xa || *s == 0xc || *s == 0xd)
  6285.         *q++= ']';
  6286.     }
  6287.     *q= '\0';
  6288.     }
  6289.     else
  6290.     strcpy( _q, string);
  6291.  
  6292.     if ( font_tag)
  6293.     q+= sprintf( q, "</font>");
  6294.  
  6295.     return _q;
  6296.  
  6297. }
  6298.  
  6299. int
  6300. is_default_rule( struct rule *rule)
  6301. {
  6302.     if ( strcmp( rule->name, "sv_maxspeed") == 0)
  6303.     return strcmp( rule->value, Q_DEFAULT_SV_MAXSPEED) == 0;
  6304.     if ( strcmp( rule->name, "sv_friction") == 0)
  6305.     return strcmp( rule->value, Q_DEFAULT_SV_FRICTION) == 0;
  6306.     if ( strcmp( rule->name, "sv_gravity") == 0)
  6307.     return strcmp( rule->value, Q_DEFAULT_SV_GRAVITY) == 0;
  6308.     if ( strcmp( rule->name, "noexit") == 0)
  6309.     return strcmp( rule->value, Q_DEFAULT_NOEXIT) == 0;
  6310.     if ( strcmp( rule->name, "teamplay") == 0)
  6311.     return strcmp( rule->value, Q_DEFAULT_TEAMPLAY) == 0;
  6312.     if ( strcmp( rule->name, "timelimit") == 0)
  6313.     return strcmp( rule->value, Q_DEFAULT_TIMELIMIT) == 0;
  6314.     if ( strcmp( rule->name, "fraglimit") == 0)
  6315.     return strcmp( rule->value, Q_DEFAULT_FRAGLIMIT) == 0;
  6316.     return 0;
  6317. }
  6318.  
  6319. char *
  6320. strherror( int h_err)
  6321. {
  6322.     static char msg[100];
  6323.     switch (h_err)  {
  6324.     case HOST_NOT_FOUND:    return "host not found";
  6325.     case TRY_AGAIN:        return "try again";
  6326.     case NO_RECOVERY:        return "no recovery";
  6327.     case NO_ADDRESS:        return "no address";
  6328.     default:    sprintf( msg, "%d", h_err); return msg;
  6329.     }
  6330. }
  6331.  
  6332. int
  6333. time_delta( struct timeval *later, struct timeval *past)
  6334. {
  6335.     if ( later->tv_usec < past->tv_usec)  {
  6336.     later->tv_sec--;
  6337.     later->tv_usec+= 1000000;
  6338.     }
  6339.     return (later->tv_sec - past->tv_sec) * 1000 +
  6340.     (later->tv_usec - past->tv_usec) / 1000;
  6341. }
  6342.  
  6343. int
  6344. connection_refused()
  6345. {
  6346. #ifdef _ISUNIX
  6347.     return errno == ECONNREFUSED;
  6348. #endif
  6349.  
  6350. #ifdef _WIN32
  6351.     return WSAGetLastError() == WSAECONNABORTED;
  6352. #endif
  6353. }
  6354.  
  6355. void
  6356. set_non_blocking( int fd)
  6357. {
  6358. #ifdef _ISUNIX
  6359. #ifdef O_NONBLOCK
  6360.     fcntl( fd, F_SETFL, O_NONBLOCK);
  6361. #else
  6362.     fcntl( fd, F_SETFL, O_NDELAY);
  6363. #endif
  6364. #endif
  6365.  
  6366. #ifdef _WIN32
  6367.     int one= 1;
  6368.     ioctlsocket( fd, FIONBIO, (unsigned long*)&one);
  6369. #endif
  6370. }
  6371.  
  6372. void
  6373. print_packet( struct qserver *server, char *buf, int buflen)
  6374. {
  6375.     static char *hex= "0123456789abcdef";
  6376.     unsigned char *p= (unsigned char*)buf;
  6377.     int i, h, a, b, offset= 0;
  6378.     char line[256];
  6379.  
  6380.     if ( server != NULL)
  6381.     fprintf( stderr, "FROM %s\n", server->arg);
  6382.  
  6383.     for ( i= buflen; i ; offset+= 16)  {
  6384.     memset( line, ' ', 256);
  6385.     h= 0;
  6386.     h+= sprintf( line, "%5d:", offset);
  6387.     a= h + 16*2 + 16/4 + 2;
  6388.     for ( b=16; b && i; b--, i--, p++)  {
  6389.         if ( (b & 3) == 0)
  6390.         line[h++]= ' ';
  6391.         line[h++]= hex[*p >> 4];
  6392.         line[h++]= hex[*p & 0xf];
  6393.         if ( isprint( *p))
  6394.         line[a++]= *p;
  6395.         else
  6396.         line[a++]= '.';
  6397.     }
  6398.     line[a]= '\0';
  6399.     fputs( line, stderr);
  6400.     fputs( "\n", stderr);
  6401.     }
  6402.     fputs( "\n", stderr);
  6403. }
  6404.  
  6405. char *
  6406. quake_color( int color)
  6407. {
  6408.     static char *colors[] = {
  6409.     "White",    /* 0 */
  6410.     "Brown",    /* 1 */
  6411.     "Lavender",    /* 2 */
  6412.     "Khaki",    /* 3 */
  6413.     "Red",        /* 4 */
  6414.     "Lt Brown",    /* 5 */
  6415.     "Peach",    /* 6 */
  6416.     "Lt Peach",    /* 7 */
  6417.     "Purple",    /* 8 */
  6418.     "Dk Purple",    /* 9 */
  6419.     "Tan",        /* 10 */
  6420.     "Green",    /* 11 */
  6421.     "Yellow",    /* 12 */
  6422.     "Blue",        /* 13 */
  6423.     "Blue",        /* 14 */
  6424.     "Blue"        /* 15 */
  6425.     };
  6426.  
  6427.     static char *rgb_colors[] = {
  6428.     "#ffffff",    /* 0 */
  6429.     "#8b4513",    /* 1 */
  6430.     "#e6e6fa",    /* 2 */
  6431.     "#f0e68c",    /* 3 */
  6432.     "#ff0000",    /* 4 */
  6433.     "#deb887",    /* 5 */
  6434.     "#eecbad",    /* 6 */
  6435.     "#ffdab9",    /* 7 */
  6436.     "#9370db",    /* 8 */
  6437.     "#5d478b",    /* 9 */
  6438.     "#d2b48c",    /* 10 */
  6439.     "#00ff00",    /* 11 */
  6440.     "#ffff00",    /* 12 */
  6441.     "#0000ff",    /* 13 */
  6442.     "#0000ff",    /* 14 */
  6443.     "#0000ff"    /* 15 */
  6444.     };
  6445.  
  6446.     if ( color_names)  {
  6447.         if ( color_names == 1)
  6448.         return colors[color&0xf];
  6449.     else
  6450.         return rgb_colors[color&0xf];
  6451.     }
  6452.     else
  6453.     return (char*)color;
  6454. }
  6455.  
  6456. char *
  6457. play_time( int seconds, int show_seconds)
  6458. {
  6459.     static char time_string[24];
  6460.     if ( time_format == CLOCK_TIME)  {
  6461.     time_string[0]= '\0';
  6462.     if ( seconds/3600)
  6463.         sprintf( time_string, "%2dh", seconds/3600);
  6464.     else
  6465.         strcat( time_string, "   ");
  6466.     if ( (seconds%3600)/60 || seconds/3600)
  6467.         sprintf( time_string+strlen(time_string), "%2dm",
  6468.         (seconds%3600)/60);
  6469.     else if ( ! show_seconds)
  6470.         sprintf( time_string+strlen(time_string), " 0m");
  6471.     else
  6472.         strcat( time_string, "   ");
  6473.     if ( show_seconds)
  6474.         sprintf( time_string+strlen(time_string), "%2ds", seconds%60);
  6475.     }
  6476.     else if ( time_format == STOPWATCH_TIME)  {
  6477.     if ( show_seconds)
  6478.         sprintf( time_string, "%02d:%02d:%02d", seconds/3600,
  6479.         (seconds%3600)/60, seconds % 60);
  6480.     else
  6481.         sprintf( time_string, "%02d:%02d", seconds/3600,
  6482.         (seconds%3600)/60);
  6483.     }
  6484.     else
  6485.     sprintf( time_string, "%d", seconds);
  6486.  
  6487.     return time_string;
  6488. }
  6489.  
  6490. char *
  6491. ping_time( int ms)
  6492. {
  6493.     static char time_string[24];
  6494.     if ( ms < 1000)
  6495.     sprintf( time_string, "%dms", ms);
  6496.     else if ( ms < 1000000)
  6497.     sprintf( time_string, "%ds", ms/1000);
  6498.     else
  6499.     sprintf( time_string, "%dm", ms/1000/60);
  6500.     return time_string;
  6501. }
  6502.  
  6503. int
  6504. count_bits( int n)
  6505. {
  6506.     int b= 0;
  6507.     for ( ; n; n>>=1)
  6508.     if ( n&1)
  6509.         b++;
  6510.     return b;
  6511. }
  6512.  
  6513. int
  6514. strcmp_withnull( char *one, char *two)
  6515. {
  6516.     if ( one == NULL && two == NULL)
  6517.     return 0;
  6518.     if ( one != NULL && two == NULL)
  6519.     return -1;
  6520.     if ( one == NULL)
  6521.     return 1;
  6522.     return strcasecmp( one, two);
  6523. }
  6524.  
  6525. /*
  6526.  * Sorting functions
  6527.  */
  6528.  
  6529. void quicksort( void **array, int i, int j, int (*compare)(void*,void*));
  6530. int qpartition( void **array, int i, int j, int (*compare)(void*,void*));
  6531.  
  6532. void
  6533. sort_servers( struct qserver **array, int size)
  6534. {
  6535.     quicksort( (void**)array, 0, size-1, (int (*)(void*,void*)) server_compare);
  6536. }
  6537.  
  6538. void
  6539. sort_players( struct qserver *server)
  6540. {
  6541.     struct player **array, *player, *last_team= NULL, **next;
  6542.     int np, i;
  6543.  
  6544.     if ( server->num_players == 0 || server->players == NULL)
  6545.     return;
  6546.  
  6547.     player= server->players;
  6548.     for ( ; player != NULL && player->number == TRIBES_TEAM; )  {
  6549.     last_team= player;
  6550.     player= player->next;
  6551.     }
  6552.     if ( player == NULL)
  6553.     return;
  6554.  
  6555.     array= (struct player **) malloc( sizeof(struct player *) *
  6556.     server->num_players);
  6557.     for ( np= 0; player != NULL && np < server->num_players; np++)  {
  6558.     array[np]= player;
  6559.     player= player->next;
  6560.     }
  6561.     quicksort( (void**)array, 0, np-1, (int (*)(void*,void*)) player_compare);
  6562.  
  6563.     if ( last_team)
  6564.     next= &last_team->next;
  6565.     else
  6566.     next= &server->players;
  6567.  
  6568.     for ( i= 0; i < np; i++)  {
  6569.     *next= array[i];
  6570.     array[i]->next= NULL;
  6571.     next= &array[i]->next;
  6572.     }
  6573.  
  6574.     free( array);
  6575. }
  6576.  
  6577. int
  6578. server_compare( struct qserver *one, struct qserver *two)
  6579. {
  6580.     int rc;
  6581.  
  6582.     char *key= sort_keys;
  6583.  
  6584.     for ( ; *key; key++)  {
  6585.     switch( *key)  {
  6586.     case 'g':
  6587.         rc= strcmp_withnull( one->game, two->game);
  6588.         if ( rc)
  6589.         return rc;
  6590.         break;
  6591.     case 'p':
  6592.         if ( one->n_requests == 0)
  6593.         return two->n_requests;
  6594.         else if ( two->n_requests == 0)
  6595.         return -1;
  6596.         rc= one->ping_total/one->n_requests -
  6597.             two->ping_total/two->n_requests;
  6598.         if ( rc)
  6599.         return rc;
  6600.         break;
  6601.     case 'i':
  6602.         if ( one->ipaddr > two->ipaddr)
  6603.         return 1;
  6604.         else if ( one->ipaddr < two->ipaddr)
  6605.         return -1;
  6606.         else if ( one->port > two->port)
  6607.         return 1;
  6608.         else if ( one->port < two->port)
  6609.         return -1;
  6610.         break;
  6611.     case 'h':
  6612.         rc= strcmp_withnull( one->host_name, two->host_name);
  6613.         if ( rc)
  6614.         return rc;
  6615.         break;
  6616.     case 'n':
  6617.         rc= two->num_players - one->num_players;
  6618.         if ( rc)
  6619.         return rc;
  6620.         break;
  6621.     }
  6622.     }
  6623.  
  6624.     return 0;
  6625. }
  6626.  
  6627. int
  6628. player_compare( struct player *one, struct player *two)
  6629. {
  6630.     int rc;
  6631.  
  6632.     char *key= sort_keys;
  6633.  
  6634.     for ( ; *key; key++)  {
  6635.     switch( *key)  {
  6636.     case 'P':
  6637.         rc= one->ping - two->ping;
  6638.         if ( rc)
  6639.         return rc;
  6640.         break;
  6641.     case 'F':
  6642.         rc= two->frags - one->frags;
  6643.         if ( rc)
  6644.         return rc;
  6645.         break;
  6646.     case 'T':
  6647.         rc= one->team - two->team;
  6648.         if ( rc)
  6649.         return rc;
  6650.         break;
  6651.     }
  6652.     }
  6653.     return 0;
  6654. }
  6655.  
  6656. void
  6657. quicksort( void **array, int i, int j, int (*compare)(void*,void*))
  6658. {
  6659.     int q= 0;
  6660.   
  6661.     if ( i < j) {
  6662.     q = qpartition(array,i,j, compare);
  6663.     quicksort(array,i,q, compare);
  6664.     quicksort(array,q+1,j, compare);
  6665.     }
  6666. }
  6667.  
  6668. int
  6669. qpartition( void **array, int a, int b, int (*compare)(void*,void*))
  6670. {
  6671.     /* this is our comparison point. when we are done
  6672.        splitting this array into 2 parts, we want all the
  6673.        elements on the left side to be less then or equal
  6674.        to this, all the elements on the right side need to
  6675.        be greater then or equal to this
  6676.     */
  6677.     void *z;
  6678.  
  6679.     /* indicies into the array to sort. Used to calculate a partition
  6680.        point
  6681.     */
  6682.     int i = a-1;
  6683.     int j = b+1;
  6684.  
  6685.     /* temp pointer used to swap two array elements */
  6686.     void * tmp = NULL;
  6687.  
  6688.     z = array[a];
  6689.  
  6690.     while (1) {
  6691.  
  6692.         /* move the right indice over until the value of that array
  6693.            elem is less than or equal to z. Stop if we hit the left
  6694.            side of the array (ie, j == a);
  6695.         */
  6696.     do {
  6697.         j--;
  6698.     } while( j > a && compare(array[j],z) > 0);
  6699.  
  6700.         /* move the left indice over until the value of that
  6701.            array elem is greater than or equal to z, or until
  6702.            we hit the right side of the array (ie i == j)
  6703.         */
  6704.     do {
  6705.         i++;
  6706.     } while( i <= j && compare(array[i],z) < 0);
  6707.  
  6708.         /* if i is less then j, we need to switch those two array
  6709.            elements, if not then we are done partitioning this array
  6710.            section
  6711.         */
  6712.     if(i < j) {
  6713.         tmp = array[i];
  6714.         array[i] = array[j];
  6715.         array[j] = tmp;
  6716.     }
  6717.     else
  6718.         return j;
  6719.     }
  6720. }
  6721.  
  6722.